home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-04-09 | 136.7 KB | 4,329 lines |
- Newsgroups: comp.sources.unix
- From: moore@cs.utk.edu (Keith Moore)
- Subject: v26i117: port-lpr - portable lpr client for USL and VMS systems, Part01/01
- Sender: unix-sources-moderator@vix.com
- Approved: paul@vix.com
-
- Submitted-By: moore@cs.utk.edu (Keith Moore)
- Posting-Number: Volume 26, Issue 117
- Archive-Name: port-lpr/part01
-
- This is a standalone lpr client that can be used to submit print jobs over a
- network to a machine that runs a Berkeley-style lpd server. The code is
- reasonably portable (not just to UNIX) in that it attempts to compensate for
- the differences in the way text files are stored on various systems.
-
- It is useful:
-
- - on a UNIX machine that doesn't support printing to remote
- Berkeley-style print queues (but which does have TCP), or
-
- - to print files to a UNIX print queue from a VAX/VMS machine, either over
- TCP/IP or DECnet. A gateway from DECnet-based lpr protocol to TCP-based
- lpr protocol is supplied, but you must have a UNIX box that speaks the
- DECnet protocol in order to use this.
-
- We use it for both purposes at UTK-CS.
-
- One of the problems with porting lpr to non-UNIX systems is the fact that
- the lpr protocol requires that the client determine the size of a file to be
- printed, as it would be stored on UNIX, before sending the file. This
- program accomplishes this by reading the entire file into memory before
- transmitting it to the UNIX system. This allows this lpr client to work on
- non-UNIX systems that store files in a different format, but as a result it
- cannot print any file that is too big to fit in memory.
-
- port-lpr is (nearly) freely redistributable under the terms of the GNU
- General Public License.
-
- Enjoy.
-
- Keith Moore
- moore@cs.utk.edu
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of shell archive."
- # Contents: BLURB README MANIFEST LICENSE ChangeLog lpr.c config.h
- # common.h patchlevel.h unix-tcp.c Makefile vms-ucx-tcp.c
- # vms-decnet.c vms-win-tcp.c descrip.mms dnet-lpd-gw.c lpr.man
- # lpr.cat
- # Wrapped by moore@thud on Thu May 21 02:16:12 1992
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'BLURB' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'BLURB'\"
- else
- echo shar: Extracting \"'BLURB'\" \(1275 characters\)
- sed "s/^X//" >'BLURB' <<'END_OF_FILE'
- This is a standalone lpr client that can be used to submit print jobs
- over a network to a machine that runs a Berkeley-style lpd server.
- The code is reasonably portable (not just to UNIX) and attempts to
- compensate for the differences in the way text files are stored on
- various systems.
- X
- It might be useful, for instance:
- X
- X- on a UNIX machine that doesn't support printing to remote
- X Berkeley-style print queues, or
- X
- X- to print files to a UNIX print queue from a VAX/VMS machine, either over
- X TCP/IP or DECnet. A gateway from DECnet-based lpr protocol to TCP-based
- X lpr protocol is supplied, but you must have a UNIX box that speaks the
- X DECnet protocol in order to use this.
- X
- One of the major problems with porting lpr to other systems is the
- fact that the lpr protocol requires that the client determine the size
- of a file to be printed, as it would be stored on UNIX, before sending
- the file. This program accomplishes this by reading the entire file
- into memory before transmitting it to the UNIX system. This allows
- this lpr client to work on non-UNIX systems that store files in a
- different format, but it cannot print any file that is too big to fit
- in memory.
- X
- port-lpr is (almost) freely redistributable under the terms of the GNU
- General Public License.
- X
- END_OF_FILE
- if test 1275 -ne `wc -c <'BLURB'`; then
- echo shar: \"'BLURB'\" unpacked with wrong size!
- fi
- # end of 'BLURB'
- fi
- if test -f 'README' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'README'\"
- else
- echo shar: Extracting \"'README'\" \(9221 characters\)
- sed "s/^X//" >'README' <<'END_OF_FILE'
- This is something I threw together to allow various non-BSD systems to
- print over the network to print queues on BSD-style systems (like
- SunOS and Ultrix and...). Basically, it's a standalone clone of the
- BSD "lpr" command -- like BSD lpr but it doesn't need a print spooler
- on the local machine. This program also runs on VMS systems, and
- there's a gateway to allow the VMS systems to talk lpr over DECnet as
- long as you have a UNIX host that also speaks DECnet which can act as
- a gateway.
- X
- If you are running UNIX, you have to have a Berkeley-style TCP
- implementation on your machine (with socket(), bind() and that sort of
- stuff), and access to an Berkeley lpd server somewhere on the network.
- If you are running VMS, you can use either DEC's Ultrix connection or
- Wollongong WIN/TCP for VMS, or you can run lpr over DECnet. The
- latter requires that you have access to a UNIX host that can speak
- DECnet (either SunLink DNI or DECnet-Ultrix), and which can talk to an
- lpr server somewhere.
- X
- At one time or another, I have tested the lpr program on SCO ODT 1.0,
- SunOS 4.1, Ultrix 3.x, Ultrix 4.x, 4.3 BSD, an IBM RS/6000 running AIX
- X3.x, and on a Stardent Titan running some variant of SysV. It also
- works on VAX/VMS 5.4 with UCX TCP and DECnet. (I got it to compile on
- a machine with an old version of WIN/TCP, but I couldn't fully test it
- because I don't have privileged access to that machine.) The dnet-lpr
- gateway program has been tested on a Sun/3 running SunOS 4.1 and
- SunLink DNI 6.0, and a DecStation 5000 running Ultrix 4.2 and
- DECnet-Ultrix.
- X
- I have used SunOS and Ultrix machines as printer servers, but I would
- expect this program to work with any lpd server running 4.2BSD or
- X4.3BSD-derived code.
- X
- X* Warranty:
- X
- READ THIS BEFORE INSTALLING THIS CODE ON ANY MACHINE:
- X
- There is NO WARRANTY for this software, not even for merchantability
- nor for fitness for any particular purpose. Anyone who installs or uses
- this software, does so entirely at his or her own risk. The author
- will not be responsible for any ill consequences of the installation
- or use of this software, no matter how terrible.
- X
- X* Copyright, use and redistribution:
- X
- The source code for this program is Copyright 1990, 1991 by Keith Moore
- X
- Use of this program and distribution of the code in either source or
- compiled binary form are governed by the GNU General Public License,
- Version 2. See the file LICENSE for details.
- X
- X* Compiling on UNIX:
- X
- On many UNIX systems you can simply type "make".
- X
- On UNIX, if your C compiler does not define the macro "unix", add a
- X"CFLAGS=-Dunix" to the "make" command line, like so:
- X
- X make CFLAGS=-Dunix
- X
- If you have SunLink DNI or DECnet-Ultrix and want to compile the
- decnet lpd gateway, type "make dnet-lpd-gw".
- X
- X* Compiling on VMS:
- X
- On VMS systems you need to edit the DESCRIP.MMS file first (assuming
- you have DEC/MMS), and pick which transport you want to use. Also, be
- sure to select the proper object library. Then type "mms" to make
- things. If you use some other "make" clone besides DEC/MMS, then you
- may have to make small changes to the DESCRIP.MMS file and rename it
- to something like MAKEFILE.
- X
- If you don't have DEC/MMS or some flavor of "make", do the following:
- X
- cc/debug lpr.c
- cc/debug DRIVER.c
- link lpr,DRIVER,LIBRARY/lib
- X
- where DRIVER and LIBRARY are chosen from the following, based on whether
- you are using UCX TCP, Wollongong TCP, or DECnet:
- X
- Transport DRIVER LIBRARY
- UCX TCP vms-ucx-tcp sys$library:ucx$ipc.olb
- WIN/TCP vms-win-tcp twg$tcp:[netdist.lib]twglib.olb
- DECnet vms-decnet (not needed)
- X
- X* UNIX Installation:
- X
- On UNIX, "make install" should do the trick to install the lpr
- program. (NOTE:: make install creates a set-uid program. See below
- under IMPORTANT NOTES for details.) You may have to edit the Makefile
- to change the installation directory. Install the man page by hand,
- if your system supports these. The file "lpr.cat" is a preformatted
- man page, in case your system does not support nroff. If your system
- has a man command, you may be able to copy the lpr.cat file into an
- appropriate directory with an appropriate name so that "man lpr" will
- work.
- X
- lpr expects a file named /etc/LPD_SERVER that contains the host name
- of a machine that has a working BSD-style line printer daemon.
- XFailing this, it checks the environment variable LPD_SERVER for the
- printer server host, so users can override the system default. Either
- of these can be manually overriden with the -S command line option.
- However the print server is specified, the client machine must have
- permission to print on the server's print queues. Generally this is
- done by editing either /etc/hosts.lpd or /etc/hosts.equiv on the
- server.
- X
- X* VMS Installation:
- X
- To run lpr on VMS, copy LPR.EXE to an appropriate directory and define a
- DCL symbol to point to it, e.g.:
- X
- lpr == "$some$system$directory:[some.sub.directory]lpr.exe"
- X
- You may need to install the image with privileges; see below.
- X
- after which it works almost, but not quite, just like on UNIX.
- Unfortunately, the VAX C library is really brain dead, so wildcards do
- not work, the entire command line is lower cased, and you can't have
- embedded spaces in file names. (The effect of the last restriction is
- that you can't use lpr to print a file on a remote DECnet node if you
- don't have proxy access to that machine.) If someone wants to
- contribute a CLD based front end for this program, I'll be happy to
- include it in a future release.
- X
- On VMS, the logical name LPD_SERVER must be defined to point to the
- name of the host acting as a print server (for TCP, this is the
- Internet domain name of the server; for DECnet, it's the DECnet node
- name of the machine where the gateway runs). This can either be
- defined by the user or as a system-wide logical name.
- X
- To do the equivalent of lprm or lpq on VMS, define symbols like the
- following:
- X
- lpq == "$some$system$directory:[some.sub.directory]lpr.exe -showqueue"
- lprm == "$some$system$directory:[some.sub.directory]lpr.exe -remove"
- X
- X* Installation of the DECnet lpr gateway on SunOS:
- X
- X(You must be running SunLink DNI to do this:)
- X
- X"make install-gw" will install the dnet-lpd-gw program in an
- appropriate directory. You might need to edit the Makefile, however,
- if /usr/sunlink/dni is not an appropriate directory on your machine.
- X"dnet-lpd-gw" is also installed set-uid to root.
- X
- The dnet-lpd-gw program should be installed so that it will be run
- with an remote DECnet client tries to connect to object 223. On Sun
- systems, do this by editing the file /usr/sunlink/dni/dniserver.reg
- and adding a line like the following:
- X
- X223 DNETLPD /usr/sunlink/dni/dnet-lpd-gw
- X
- X(Currently, the number 223 is wired into vms-decnet.c. This may
- change at some point.) "make install-gw" will copy dnet-lpd-gw to the
- X/usr/sunlink/dni directory and install it with appropriate
- permissions.
- X
- X* Installation of the DECnet lpr gateway on Ultrix:
- X
- X(You have to be running DECnet-Ultrix to do this:)
- X
- Become root and use the "ncp" program to define the DNETLPD object as follows:
- X
- X# ncp
- ncp>clear object dnetlpd
- ncp>set object dnetlpd
- Number : 223
- XFile : /usr/local/lib/dnet-lpd-gw
- Default User : daemon
- Type : sequenced packet
- Accept : deferred
- ncp> ^D
- X
- X(Note: you can set the "default user" to "root" instead of "daemon",
- in which case dnet-lpd-gw need not be set-uid to root. The set-uid
- approach is probably safer in this case.)
- X
- X* IMPORTANT NOTES:
- X
- On UNIX, the program is installed set-uid to root, which is necessary
- so that lpr can bind to a privileged TCP port. This should not
- present a security risk since the first thing that the program does is
- to create the socket and bind it to the privileged port, after which
- it immediately disables its special privileges. All file opens,
- reads, etc., are then done with the invoking user's normal privileges.
- X
- On VMS, similar concerns apply if using TCP -- the program must be
- installed as a privileged image with the INSTALL utility. UCX TCP
- requires either BYPASS or SYSPRV privilege in order to allow lpr to
- bind to a privileged port. I'm not sure offhand what privileges
- WIN/TCP requires. Anyway, immediately after successfully binding to a
- privileged port, the lpr program turns off all image-installed
- privileges.
- X
- XFor VMS systems using a DECnet-based lpr, no special installation is
- required, but the UNIX-based server does have to be installed set-uid
- to root. If when using lpr over DECnet you get the message "your host
- does not have line printer access", you need to put "localhost" or the
- hostname of the print server in the print server machine's
- X/etc/hosts.lpd file. You may then have to kill and restart lpd on the
- server to get it to recognize the changed /etc/hosts.lpd file.
- X
- X* Miscellaneous:
- X
- The UNIX Makefile has rules to generate this package in various
- formats to allow it to be moved from system to system. Of special
- interest is the rule for "make port-lpr.vms", which creates a VMS .COM
- file that extracts itself when run in an empty VMS directory.
- X
- Sorry, there's no special HELP file for lpr on VMS. Perhaps someone
- will contribute one.
- X
- If you find bugs and can supply fixes, please let me know and I'll try
- and have the fixes incorporated into a future release.
- X
- Keith Moore
- moore@cs.utk.edu
- END_OF_FILE
- if test 9221 -ne `wc -c <'README'`; then
- echo shar: \"'README'\" unpacked with wrong size!
- fi
- # end of 'README'
- fi
- if test -f 'MANIFEST' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'MANIFEST'\"
- else
- echo shar: Extracting \"'MANIFEST'\" \(809 characters\)
- sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
- README - general information file
- MANIFEST - this file
- LICENSE - GNU General Public License, Version 1, which applies to this source
- ChangeLog - history of source changes
- lpr.c - main program
- config.h - trivial config file.
- Makefile - you do use make, don't you?
- unix-tcp.c - back-end interface for UNIX systems with BSD socket libraries
- vms-ucx-tcp.c - back-end interface for VMS systems with UCX tcp
- vms-win-tcp.c - back-end interface for VMS systems with Wollongong WIN/TCP
- vms-decnet.c - back-end interface for VMS systems using DECnet-VAX
- descrip.mms - Makefile for VMS systems using DEC/MMS
- dnet-lpd-gw.c - UNIX program that gateways DECnet-based lpr to the local
- X print spooler
- lpr.man - {n,t}roff source for lpr man page
- lpr.cat - preformatted man page for those systems that don't have nroff
- END_OF_FILE
- if test 809 -ne `wc -c <'MANIFEST'`; then
- echo shar: \"'MANIFEST'\" unpacked with wrong size!
- fi
- # end of 'MANIFEST'
- fi
- if test -f 'LICENSE' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'LICENSE'\"
- else
- echo shar: Extracting \"'LICENSE'\" \(17982 characters\)
- sed "s/^X//" >'LICENSE' <<'END_OF_FILE'
- X GNU GENERAL PUBLIC LICENSE
- X Version 2, June 1991
- X
- X Copyright (C) 1989, 1991 Free Software Foundation, Inc.
- X 675 Mass Ave, Cambridge, MA 02139, USA
- X Everyone is permitted to copy and distribute verbatim copies
- X of this license document, but changing it is not allowed.
- X
- X Preamble
- X
- X The licenses for most software are designed to take away your
- freedom to share and change it. By contrast, the GNU General Public
- License is intended to guarantee your freedom to share and change free
- software--to make sure the software is free for all its users. This
- General Public License applies to most of the Free Software
- XFoundation's software and to any other program whose authors commit to
- using it. (Some other Free Software Foundation software is covered by
- the GNU Library General Public License instead.) You can apply it to
- your programs, too.
- X
- X When we speak of free software, we are referring to freedom, not
- price. Our General Public Licenses are designed to make sure that you
- have the freedom to distribute copies of free software (and charge for
- this service if you wish), that you receive source code or can get it
- if you want it, that you can change the software or use pieces of it
- in new free programs; and that you know you can do these things.
- X
- X To protect your rights, we need to make restrictions that forbid
- anyone to deny you these rights or to ask you to surrender the rights.
- These restrictions translate to certain responsibilities for you if you
- distribute copies of the software, or if you modify it.
- X
- X For example, if you distribute copies of such a program, whether
- gratis or for a fee, you must give the recipients all the rights that
- you have. You must make sure that they, too, receive or can get the
- source code. And you must show them these terms so they know their
- rights.
- X
- X We protect your rights with two steps: (1) copyright the software, and
- X(2) offer you this license which gives you legal permission to copy,
- distribute and/or modify the software.
- X
- X Also, for each author's protection and ours, we want to make certain
- that everyone understands that there is no warranty for this free
- software. If the software is modified by someone else and passed on, we
- want its recipients to know that what they have is not the original, so
- that any problems introduced by others will not reflect on the original
- authors' reputations.
- X
- X Finally, any free program is threatened constantly by software
- patents. We wish to avoid the danger that redistributors of a free
- program will individually obtain patent licenses, in effect making the
- program proprietary. To prevent this, we have made it clear that any
- patent must be licensed for everyone's free use or not licensed at all.
- X
- X The precise terms and conditions for copying, distribution and
- modification follow.
- X
- X GNU GENERAL PUBLIC LICENSE
- X TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
- X
- X 0. This License applies to any program or other work which contains
- a notice placed by the copyright holder saying it may be distributed
- under the terms of this General Public License. The "Program", below,
- refers to any such program or work, and a "work based on the Program"
- means either the Program or any derivative work under copyright law:
- that is to say, a work containing the Program or a portion of it,
- either verbatim or with modifications and/or translated into another
- language. (Hereinafter, translation is included without limitation in
- the term "modification".) Each licensee is addressed as "you".
- X
- Activities other than copying, distribution and modification are not
- covered by this License; they are outside its scope. The act of
- running the Program is not restricted, and the output from the Program
- is covered only if its contents constitute a work based on the
- Program (independent of having been made by running the Program).
- Whether that is true depends on what the Program does.
- X
- X 1. You may copy and distribute verbatim copies of the Program's
- source code as you receive it, in any medium, provided that you
- conspicuously and appropriately publish on each copy an appropriate
- copyright notice and disclaimer of warranty; keep intact all the
- notices that refer to this License and to the absence of any warranty;
- and give any other recipients of the Program a copy of this License
- along with the Program.
- X
- You may charge a fee for the physical act of transferring a copy, and
- you may at your option offer warranty protection in exchange for a fee.
- X
- X 2. You may modify your copy or copies of the Program or any portion
- of it, thus forming a work based on the Program, and copy and
- distribute such modifications or work under the terms of Section 1
- above, provided that you also meet all of these conditions:
- X
- X a) You must cause the modified files to carry prominent notices
- X stating that you changed the files and the date of any change.
- X
- X b) You must cause any work that you distribute or publish, that in
- X whole or in part contains or is derived from the Program or any
- X part thereof, to be licensed as a whole at no charge to all third
- X parties under the terms of this License.
- X
- X c) If the modified program normally reads commands interactively
- X when run, you must cause it, when started running for such
- X interactive use in the most ordinary way, to print or display an
- X announcement including an appropriate copyright notice and a
- X notice that there is no warranty (or else, saying that you provide
- X a warranty) and that users may redistribute the program under
- X these conditions, and telling the user how to view a copy of this
- X License. (Exception: if the Program itself is interactive but
- X does not normally print such an announcement, your work based on
- X the Program is not required to print an announcement.)
- X
- These requirements apply to the modified work as a whole. If
- identifiable sections of that work are not derived from the Program,
- and can be reasonably considered independent and separate works in
- themselves, then this License, and its terms, do not apply to those
- sections when you distribute them as separate works. But when you
- distribute the same sections as part of a whole which is a work based
- on the Program, the distribution of the whole must be on the terms of
- this License, whose permissions for other licensees extend to the
- entire whole, and thus to each and every part regardless of who wrote it.
- X
- Thus, it is not the intent of this section to claim rights or contest
- your rights to work written entirely by you; rather, the intent is to
- exercise the right to control the distribution of derivative or
- collective works based on the Program.
- X
- In addition, mere aggregation of another work not based on the Program
- with the Program (or with a work based on the Program) on a volume of
- a storage or distribution medium does not bring the other work under
- the scope of this License.
- X
- X 3. You may copy and distribute the Program (or a work based on it,
- under Section 2) in object code or executable form under the terms of
- Sections 1 and 2 above provided that you also do one of the following:
- X
- X a) Accompany it with the complete corresponding machine-readable
- X source code, which must be distributed under the terms of Sections
- X 1 and 2 above on a medium customarily used for software interchange; or,
- X
- X b) Accompany it with a written offer, valid for at least three
- X years, to give any third party, for a charge no more than your
- X cost of physically performing source distribution, a complete
- X machine-readable copy of the corresponding source code, to be
- X distributed under the terms of Sections 1 and 2 above on a medium
- X customarily used for software interchange; or,
- X
- X c) Accompany it with the information you received as to the offer
- X to distribute corresponding source code. (This alternative is
- X allowed only for noncommercial distribution and only if you
- X received the program in object code or executable form with such
- X an offer, in accord with Subsection b above.)
- X
- The source code for a work means the preferred form of the work for
- making modifications to it. For an executable work, complete source
- code means all the source code for all modules it contains, plus any
- associated interface definition files, plus the scripts used to
- control compilation and installation of the executable. However, as a
- special exception, the source code distributed need not include
- anything that is normally distributed (in either source or binary
- form) with the major components (compiler, kernel, and so on) of the
- operating system on which the executable runs, unless that component
- itself accompanies the executable.
- X
- If distribution of executable or object code is made by offering
- access to copy from a designated place, then offering equivalent
- access to copy the source code from the same place counts as
- distribution of the source code, even though third parties are not
- compelled to copy the source along with the object code.
- X
- X 4. You may not copy, modify, sublicense, or distribute the Program
- except as expressly provided under this License. Any attempt
- otherwise to copy, modify, sublicense or distribute the Program is
- void, and will automatically terminate your rights under this License.
- However, parties who have received copies, or rights, from you under
- this License will not have their licenses terminated so long as such
- parties remain in full compliance.
- X
- X 5. You are not required to accept this License, since you have not
- signed it. However, nothing else grants you permission to modify or
- distribute the Program or its derivative works. These actions are
- prohibited by law if you do not accept this License. Therefore, by
- modifying or distributing the Program (or any work based on the
- Program), you indicate your acceptance of this License to do so, and
- all its terms and conditions for copying, distributing or modifying
- the Program or works based on it.
- X
- X 6. Each time you redistribute the Program (or any work based on the
- Program), the recipient automatically receives a license from the
- original licensor to copy, distribute or modify the Program subject to
- these terms and conditions. You may not impose any further
- restrictions on the recipients' exercise of the rights granted herein.
- You are not responsible for enforcing compliance by third parties to
- this License.
- X
- X 7. If, as a consequence of a court judgment or allegation of patent
- infringement or for any other reason (not limited to patent issues),
- conditions are imposed on you (whether by court order, agreement or
- otherwise) that contradict the conditions of this License, they do not
- excuse you from the conditions of this License. If you cannot
- distribute so as to satisfy simultaneously your obligations under this
- License and any other pertinent obligations, then as a consequence you
- may not distribute the Program at all. For example, if a patent
- license would not permit royalty-free redistribution of the Program by
- all those who receive copies directly or indirectly through you, then
- the only way you could satisfy both it and this License would be to
- refrain entirely from distribution of the Program.
- X
- If any portion of this section is held invalid or unenforceable under
- any particular circumstance, the balance of the section is intended to
- apply and the section as a whole is intended to apply in other
- circumstances.
- X
- It is not the purpose of this section to induce you to infringe any
- patents or other property right claims or to contest validity of any
- such claims; this section has the sole purpose of protecting the
- integrity of the free software distribution system, which is
- implemented by public license practices. Many people have made
- generous contributions to the wide range of software distributed
- through that system in reliance on consistent application of that
- system; it is up to the author/donor to decide if he or she is willing
- to distribute software through any other system and a licensee cannot
- impose that choice.
- X
- This section is intended to make thoroughly clear what is believed to
- be a consequence of the rest of this License.
- X
- X 8. If the distribution and/or use of the Program is restricted in
- certain countries either by patents or by copyrighted interfaces, the
- original copyright holder who places the Program under this License
- may add an explicit geographical distribution limitation excluding
- those countries, so that distribution is permitted only in or among
- countries not thus excluded. In such case, this License incorporates
- the limitation as if written in the body of this License.
- X
- X 9. The Free Software Foundation may publish revised and/or new versions
- of the General Public License from time to time. Such new versions will
- be similar in spirit to the present version, but may differ in detail to
- address new problems or concerns.
- X
- XEach version is given a distinguishing version number. If the Program
- specifies a version number of this License which applies to it and "any
- later version", you have the option of following the terms and conditions
- either of that version or of any later version published by the Free
- Software Foundation. If the Program does not specify a version number of
- this License, you may choose any version ever published by the Free Software
- XFoundation.
- X
- X 10. If you wish to incorporate parts of the Program into other free
- programs whose distribution conditions are different, write to the author
- to ask for permission. For software which is copyrighted by the Free
- Software Foundation, write to the Free Software Foundation; we sometimes
- make exceptions for this. Our decision will be guided by the two goals
- of preserving the free status of all derivatives of our free software and
- of promoting the sharing and reuse of software generally.
- X
- X NO WARRANTY
- X
- X 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
- XFOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
- OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
- PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
- OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
- TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
- PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
- REPAIR OR CORRECTION.
- X
- X 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
- WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
- REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
- INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
- OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
- TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
- YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
- PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
- POSSIBILITY OF SUCH DAMAGES.
- X
- X END OF TERMS AND CONDITIONS
- X
- X Appendix: How to Apply These Terms to Your New Programs
- X
- X If you develop a new program, and you want it to be of the greatest
- possible use to the public, the best way to achieve this is to make it
- free software which everyone can redistribute and change under these terms.
- X
- X To do so, attach the following notices to the program. It is safest
- to attach them to the start of each source file to most effectively
- convey the exclusion of warranty; and each file should have at least
- the "copyright" line and a pointer to where the full notice is found.
- X
- X <one line to give the program's name and a brief idea of what it does.>
- X Copyright (C) 19yy <name of author>
- X
- X This program is free software; you can redistribute it and/or modify
- X it under the terms of the GNU General Public License as published by
- X the Free Software Foundation; either version 2 of the License, or
- X (at your option) any later version.
- X
- X This program is distributed in the hope that it will be useful,
- X but WITHOUT ANY WARRANTY; without even the implied warranty of
- X MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- X GNU General Public License for more details.
- X
- X You should have received a copy of the GNU General Public License
- X along with this program; if not, write to the Free Software
- X Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- X
- Also add information on how to contact you by electronic and paper mail.
- X
- If the program is interactive, make it output a short notice like this
- when it starts in an interactive mode:
- X
- X Gnomovision version 69, Copyright (C) 19yy name of author
- X Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- X This is free software, and you are welcome to redistribute it
- X under certain conditions; type `show c' for details.
- X
- The hypothetical commands `show w' and `show c' should show the appropriate
- parts of the General Public License. Of course, the commands you use may
- be called something other than `show w' and `show c'; they could even be
- mouse-clicks or menu items--whatever suits your program.
- X
- You should also get your employer (if you work as a programmer) or your
- school, if any, to sign a "copyright disclaimer" for the program, if
- necessary. Here is a sample; alter the names:
- X
- X Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- X `Gnomovision' (which makes passes at compilers) written by James Hacker.
- X
- X <signature of Ty Coon>, 1 April 1989
- X Ty Coon, President of Vice
- X
- This General Public License does not permit incorporating your program into
- proprietary programs. If your program is a subroutine library, you may
- consider it more useful to permit linking proprietary applications with the
- library. If this is what you want to do, use the GNU Library General
- Public License instead of this License.
- END_OF_FILE
- if test 17982 -ne `wc -c <'LICENSE'`; then
- echo shar: \"'LICENSE'\" unpacked with wrong size!
- fi
- # end of 'LICENSE'
- fi
- if test -f 'ChangeLog' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'ChangeLog'\"
- else
- echo shar: Extracting \"'ChangeLog'\" \(8268 characters\)
- sed "s/^X//" >'ChangeLog' <<'END_OF_FILE'
- Thu May 21 01:30:35 1992 Keith Moore (moore@wilma)
- X
- X * compiled and tested decnet gw code on ultrix. Quickly tried
- X to fix bogus error codes on vms and generally failed.
- X
- X * README: corrected/updated to reflect more recent changes
- X
- X * LICENSE: is now GPLv2
- X
- X * lpr.man: known bug list updated.
- X
- X * patchlevel.h: updated minor version (patchlevel) to 4, because
- X I had released container files with version 1.2 and 1.3. New
- X container files will be version 1.4.
- X
- Thu Dec 12 01:03:55 1991 Keith Moore (moore at wilma)
- X
- X * lpr.c (append_string_to_buffer, read_file_into_buffer):
- X made them return a pointer to the buffer, in case realloc()
- X (in enlarge_buffer()) had to move the buffer somewhere else.
- X
- X * lpr.c (control): reassign job->cfile to the value returned
- X from append_string_to_buffer()
- X
- X * lpr.c (send_print_file): respect return value from
- X read_file_into_buffer()
- X
- X (lpr now accepts large files from stdin again)
- X
- Wed Dec 4 00:42:58 1991 Keith Moore (moore at wilma)
- X
- X * unix-tcp.c, vms-decnet.c, vms-ucx-tcp.c: fix typo in error
- X msg.
- X
- X * lpr.c (lprm): Initialize remove_all flag to zero.
- X Fix the case where no args are supplied.
- X
- X * lpr.c (get_lpd_server): add check in case fscanf() fails.
- X (could happen if file is empty) Cast return value to
- X (char *) to placate fussy DEC compiler.
- X
- Thu Sep 12 23:54:29 1991 Keith Moore (moore at wilma)
- X
- X * lpr.c (get_lpd_server): new function
- X
- X * lpr and friends now look for a file named /etc/LPD_SERVER to
- X get the default printer server. Or you can still specify
- X -S printer-server on the command-line.
- X
- XFri Sep 6 12:22:09 1991 Keith Moore (moore at wilma)
- X
- X * [various tcp modules] (get_priv_tcp_socket):
- X if all attempts to bind to a privileged port fail, close socket
- X and return EOF.
- X
- Thu Jul 25 00:34:06 1991 Keith Moore (moore at chili)
- X
- X
- X file lpr.c:
- X
- X * add lpq and lprm functions: if argv[0] ends
- X in "lpq" or "lprm", behave like those commands. Also
- X add -showqueue and -remove options for use on VMS.
- X
- X (real_option):
- X * -f now means "print a FORTRAN output file"
- X * -r now means "remove file after spooling" - it was being
- X construed as "print a FORTRAN output file" because the
- X lpd protocol command to do this is 'r'.
- X * added -S option to specify printer server.
- X
- X (guess_file_type)
- X * Don't print a message when we realize it's a PostScript
- X file, because there's no special command-line option for
- X these.
- X
- X (dump_buf)
- X * mask each byte with 0xff before printing in octal.
- X * Also format output a little nicer.
- X
- X file lpr.man:
- X
- X * change text regarding -f and -r options;
- X remove a diagnostic message that is no longer used
- X (still need to document lprm, lpq, and
- X -remove, -showqueue options)
- X
- X files unix-tcp.c,vms-win-tcp.c,vms-ucx-tcp.c:
- X
- X (gethostbynameoraddr)
- X * added new function.
- X if hostname argument begins with a digit, it is assumed to be
- X an IP address, and gethostbynameoraddr() will simply fill in the
- X correct fields in the hostent structure without doing an address
- X lookup. Otherwise it returns the result of gethostbyname()
- X
- X * in open_lpd(), call gethostbynameoraddr() to get IP address
- X
- X
- Thu May 9 19:26:30 1991 Keith Moore (moore at chili)
- X
- X * lpr.c: make a more informative error message when remote
- X server refuses to accept a print job.
- X
- X * vms-ucx-tcp.c, vms-win-tcp.c, unix-tcp.c (get_priv_tcp_socket):
- X don't exit, just give warning if EACCES error occurs trying to
- X bind to privileged port -- some lpd's don't require this anyway.
- X
- XFri Apr 12 16:57:13 1991 Keith Moore (moore at chili)
- X
- X * README: added some additional instructions for compiling
- X on VMS.
- X
- X * Makefile: fixed rule for port-lpr.vms that was always
- X appending the new archive onto an existing port-lpr.vms
- X file.
- X
- Tue Apr 9 21:16:31 1991 Keith Moore (moore at chili)
- X
- X * released as version 1.1
- X
- X * lpr.man: picked up some nits.
- X
- Tue Apr 9 20:37:40 1991 Keith Moore (moore at chili)
- X
- X * Makefile (clean): do "rm -f" instead of "rm"
- X
- X * dnet-lpd-gw.c (accept_decnet_connection):
- X added support for DECnet-Ultrix. Fixed typo that was setting
- X DECnet_remoteNode to the name of the remote user.
- X
- X * README: add notes about DECnet-Ultrix support for gateway.
- X
- X * BLURB: new file - capsule description of package.
- X
- Sat Mar 30 02:04:45 1991 Keith Moore (moore at chili)
- X
- X * lpr.man, README, MANIFEST - updated
- X
- X * descrip.mms: makefile for vms - created
- X
- X * Makefile: updated to reflect new changes, and also to
- X create a simple shar file for VMS
- X
- X * dnet-lpd-gw.c - new program - gateway lpr over DECnet to
- X a TCP-based lpr daemon.
- X
- X * vms-decnet.c - new module - send lpr protocol over DECnet
- X instead of TCP.
- X
- X * vms-*.c - translate_logical_name(), get_decnet_node_name()
- X new functions. Use translate_logical_name() instead of getenv()
- X to prevent spoofing of important logical names.
- X
- X * vms-*.c, unix-tcp.c - add support for MAKE_EMAIL_ADDRESS macro to
- X override default way of sending mail to whomever submitted the job.
- X
- X * TO DO:
- X add ultrix support for dnet-lpd-gw.c
- X add authentication to dnet-lpd-gw.c
- X The email address hacks don't work -- even if the client tells
- X the server that the user's email address is terre.dnet.utk.edu,
- X the server still sends mail to simply "user@terre" on job
- X completion. Fix this somehow.
- X
- XFri Mar 29 14:54:51 1991 Keith Moore (moore at chili)
- X
- X * unix-tcp.c, vms-ucx-tcp.c, vms-win-tcp.c (open_lpd):
- X changed to accept an argument to open_lpd specifying
- X what host to use as a printer server.
- X
- X * lpr.c: changed called to open_lpd to pass host name of
- X printer server as an argument, rather than implicitly
- X through the variable lpd_server.
- X
- X * makefile.vms: new makefile for VMS make, or some reasonable
- X facsimile thereof
- X
- X * config.h: We don't really need this anymore to specify which
- X kind of tcp/decnet we are using, but we do need it to specify
- X things like how to generate the user's email address back to
- X a VMS machine...definitely a site-specific option.
- X
- X * extracted network- and system-specific code into separate
- X modules: unix-tcp.c, vms-ucx-tcp.c, and vms-decnet.c
- X
- X * lpr.c (main) Was redeclaring the printer environment
- X variable, thus any -P printer option was not working.
- X
- X * lpr.c (option) Fixed bug in option parsing. I was using
- X strchr (opt, "P#CJTi1234w") to see if the opt character
- X was in that set of characters. The arguments should have been
- X reversed -- now they are. Also, "opt" should have been "opt[1]"
- X Also added 'q' to that set, so -q printer will work. (This is
- X for VMS, which lower-cases all command-line arguments unless you
- X put them in quotes.)
- X
- X * TO DO:
- X On vms, expand wildcard filenames (yuk!)
- X Build alternate argument parser for VMS.
- X Make sure we print out any error messages returned from server.
- X
- X
- Thu Mar 28 16:30:09 1991 Keith Moore (moore at chili)
- X
- X * if a host has multiple IP addresses, attempt to connect to
- X each of them before giving up. If debug is set, print out
- X each IP address as we try it.
- X
- X * converted to "Classic" (non-ANSI) C (Yuk!). GNU cc doesn't let
- X us pass a struct in_addr to inet_ntoa() because of differences
- X between argument passing conventions between gcc and the system-
- X supplied cc (with which the inet_ntoa() routine was compiled).
- X (At least this is true on a SPARC running SunOS 4.1.1)
- X
- X * added code to let lpr run on VMS with UCX TCP.
- X
- Tue Mar 26 21:53:52 1991 Keith Moore (moore at chili)
- X
- X * lpr.c (sysdep): call endpwent() after calling getpwuid() just
- X to make sure the file descriptor for /etc/passwd is closed.
- X (This is just paranoia-for-security - we don't exec anything
- X anyway, so there's no way for some program to inherit that file
- X descriptor.)
- X
- X * lpr.c (real_option): add newline after version info when -debug
- X is set
- X
- X * README: add note about compiling, and that this works on an
- X IBM RS/6000 running AIX.
- X
- Thu Mar 21 19:50:34 1991 Keith Moore (moore at chili)
- X
- X * packaged this up and sent it out as version 1.0
- X
- X * if "printer" is not defined in /etc/services, just assume that
- X we want to use port 515.
- X
- X * wrote a man page and README.
- X
- X * added a note referencing the GNU General Public License.
- X
- END_OF_FILE
- if test 8268 -ne `wc -c <'ChangeLog'`; then
- echo shar: \"'ChangeLog'\" unpacked with wrong size!
- fi
- # end of 'ChangeLog'
- fi
- if test -f 'lpr.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'lpr.c'\"
- else
- echo shar: Extracting \"'lpr.c'\" \(25058 characters\)
- sed "s/^X//" >'lpr.c' <<'END_OF_FILE'
- X/*
- X * "lpr" program for systems that don't have lpd but can talk to a system
- X * that does using TCP or DECnet
- X *
- X * Copyright (C) 1990, 1991 Keith Moore
- X
- X * This program is free software; you can redistribute it and/or modify
- X * it under the terms of the GNU General Public License, Version 1,
- X * as published by the Free Software Foundation.
- X *
- X * This program is distributed in the hope that it will be useful,
- X * but WITHOUT ANY WARRANTY; without even the implied warranty of
- X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- X * GNU General Public License for more details.
- X *
- X * You should have received a copy of the GNU General Public License
- X * along with this program; if not, write to the Free Software
- X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- X *
- X * Written by Keith Moore, December 1990
- X * Email: moore@cs.utk.edu (Internet) moore@utkvx (BITNET)
- X * Snail: Box 16320 / Knoxville TN 37996 / USA
- X */
- X
- X/* TO DO:
- X * - send troff font names
- X * - add support for /etc/printcap files.
- X * - special hacks for Imagen and/or PostScript printers (maybe)
- X * - support -i (indent) and -w (page width) options
- X * - handle huge files too big to read into memory (UNIX systems only)
- X * - recognize ditroff, raster, cifplot, and FORTRAN output files (maybe)
- X * - handle multiple lpd servers -- try each until we find one that's up.
- X * - allow printer names of the form printer@host or host::printer,
- X * - add an option to specify job-id (for use when using this program
- X * as the back-end to another print spooling system -- you can keep the
- X * job-ids the same on both systems if you're lucky).
- X * - add an option to wait until the job is actually printed -- this is
- X * not easy to do but is very useful when this program is being used
- X * as the back-end to another kind of print spooler.
- X */
- X
- X/*
- X * #define MAIN_PROGRAM here so common.h will allocate storage for the
- X * variables defined there instead of making them external references.
- X */
- X
- X#define MAIN_PROGRAM
- X#include "config.h"
- X#include "common.h"
- X#include "patchlevel.h"
- X#include <stdio.h>
- X#include <ctype.h>
- X
- X#ifdef unix
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#define EXIT_OK 0
- X#define EXIT_FAIL 1
- X#endif
- X
- X#ifdef vms
- X#include <types.h>
- X#include <stat.h>
- X#define EXIT_OK 0
- X#define EXIT_FAIL 2
- X#endif
- X
- X#define VERSION 1
- X
- X/*
- X * options...not all of which are supported
- X */
- char *printer; /* name of remote print queue */
- char *lpd_server; /* name of the remote printer server */
- char file_type = '?'; /* kind of file to be printed */
- char *title = NULL; /* page headings for pr */
- char *jobtitle = NULL; /* job name */
- char *jobclass = NULL; /* job class */
- int num_copies = 1; /* number of copies to print */
- int indent = 0; /* # of spaces to indent */
- int page_width = 72; /* page width for pr */
- char *fontnames[4]; /* names of troff fonts */
- int lflag = 0; /* if lpq, list in long format */
- int rflag = 0; /* if 1, remove file after spooling */
- int mflag = 0; /* if 1, send mail on completion */
- int hflag = 0; /* if 1, omit burst page */
- X
- X/* debug option flag is declared in common.h */
- X
- X#define min(a,b) ((a) < (b) ? (a) : (b))
- char *getenv ();
- char *calloc ();
- char *realloc ();
- char *strrchr ();
- X
- X/*
- X * debugging routines
- X */
- X
- void
- dump_buf (fp, prefix, buf, size)
- XFILE *fp; char *prefix; char *buf; unsigned size;
- X{
- X if (size > 0)
- X fprintf (fp, "%s", prefix);
- X while (size > 0){
- X if (*buf >= ' ' && *buf <= '~')
- X putc (*buf, fp);
- X else if (*buf == '\n') {
- X fprintf (fp, "\\n");
- X if (size > 1)
- X fprintf (fp, "\n%*s", strlen (prefix), "");
- X }
- X else
- X fprintf (fp, "\\%03o", *buf & 0xff);
- X ++buf;
- X --size;
- X }
- X fprintf (fp, "\n");
- X}
- X
- X
- int
- x_read (fd, buf, size)
- int fd; char *buf; unsigned size;
- X{
- X int nread = read (fd, (char *) buf, size);
- X if (debug)
- X dump_buf (stderr, "<<<", buf, nread);
- X return nread;
- X}
- X
- int
- x_write (fd, buf, size)
- int fd; char *buf; unsigned size;
- X{
- X if (debug)
- X dump_buf (stderr, ">>>", buf, size);
- X return write (fd, (char *) buf, size);
- X}
- X
- int
- y_write (fd, buf, size)
- int fd; char *buf; unsigned size;
- X{
- X if (debug)
- X fprintf (stderr, ">>> (%d bytes)\n", size);
- X return write (fd, (char *) buf, size);
- X}
- X
- X
- X/*
- X * parse an option with an optional argument (which may be NULL)
- X * return 1 if optional argument used, else 0
- X * (one of these days I'll start using getopt())
- X */
- int
- real_option (opt, arg)
- char *opt; char *arg;
- X{
- X if (opt[1] && opt[2] == '\0') {
- X /* single letter options */
- X switch (opt[1]) {
- X /*
- X * file types
- X */
- X case 'l': /* text file with embedded control chars */
- X file_type = 'l';
- X lflag++; /* or -l (long) option for lpq */
- X return 0;
- X case 'f': /* Fortran output file with carraige control */
- X file_type = 'r';
- X return 0;
- X case 'c': /* cifplot (Caltech Intermediate Form) file */
- X case 'd': /* TeX .dvi file */
- X case 'g': /* UNIX plot file */
- X case 'n': /* ditroff output file */
- X case 'o': /* PostScript file ??? */
- X case 'p': /* text file (add page headers using pr) */
- X case 't': /* C/A/T troff output file*/
- X case 'v': /* Versatec output file */
- X file_type = opt[1];
- X return 0;
- X /*
- X * job options
- X */
- X case 'P': /* -P printer */
- X case 'q': /* -q queue (same thing) */
- X printer = arg;
- X return 1;
- X case 'S': /* specify name of printer server */
- X lpd_server = arg;
- X return 1;
- X case '#': /* num copies */
- X if (arg && isdigit (*arg)) {
- X num_copies = atoi (arg);
- X return 1;
- X }
- X break;
- X case 'C': /* job class (default: local hostname) */
- X jobclass = arg;
- X return 1;
- X case 'J': /* job title (default: first file name) */
- X jobtitle = arg;
- X return 1;
- X case 'i': /* indent output (default: 8 chars) */
- X if (arg && isdigit (*arg)) {
- X indent = atoi (arg);
- X return 1;
- X }
- X else {
- X indent = 8;
- X return 0;
- X }
- X case '1': /* troff font names */
- X case '2':
- X case '3':
- X case '4':
- X fontnames[opt[1]-'1']=arg;
- X return 1;
- X case 'w': /* cols -- page width for pr */
- X if (arg && isdigit (*arg)) {
- X page_width = atoi (arg);
- X return 1;
- X }
- X case 'r': /* remove file after spooling */
- X rflag = 1;
- X return 0;
- X case 'm': /* send mail upon completion */
- X mflag = 1;
- X return 0;
- X case 'h': /* don't print the burst page */
- X hflag = 1;
- X return 0;
- X case 's': /* don't copy file -- symlink it */
- X fprintf (stderr,
- X "lpr: The -s (symlink) option is not supported\n");
- X fprintf (stderr,
- X "All files will be copied to the remote server\n");
- X return 0;
- X }
- X }
- X if (strcmp (opt, "-debug") == 0) {
- X debug = 1;
- X fprintf (stderr, "standalone lpr version %d.%d\n",
- X VERSION, PATCHLEVEL);
- X return 0;
- X }
- X fprintf (stderr, "lpr: warning: illegal option %s\n", opt);
- X return 0;
- X}
- X
- int
- option (opt, optarg)
- char *opt; char *optarg;
- X{
- X /*
- X * This hack is used to notice whether the argument for an option
- X * is appended to the option itself (e.g. "-Pprinter" rather than
- X * "-P" "printer". If this is the case, and the option accepts an
- X * argument, split the arg into two args and call real_option().
- X * otherwise just pass our args to real_option().
- X */
- X
- X if (opt[2] && strchr ("SP#CJTi1234qw", opt[1])) {
- X char temp[3];
- X temp[0] = '-';
- X temp[1] = opt[1];
- X temp[2] = '\0';
- X real_option (temp, opt + 2);
- X return 0;
- X }
- X else
- X return real_option (opt, optarg);
- X}
- X
- X/*
- X * keep up with files to be deleted (for when using -r)
- X * This is so we don't delete files until we *know* that the job
- X * has been successfully submitted.
- X */
- X
- struct delete_list {
- X char *name;
- X struct delete_list *next;
- X} *head = NULL;
- X
- void
- mark_for_delete (name)
- char *name;
- X{
- X struct delete_list *ptr = (struct delete_list *)
- X calloc (1, sizeof (struct delete_list));
- X if (!ptr) {
- X perror ("calloc");
- X return;
- X }
- X ptr->next = head;
- X ptr->name = name;
- X head = ptr;
- X}
- X
- void
- delete_marked_files ()
- X{
- X struct delete_list *ptr;
- X for (ptr = head; ptr; ptr=ptr->next) {
- X if (ptr->name)
- X if (unlink (ptr->name) < 0) {
- X fprintf (stderr, "lpr: could not delete %s\n", ptr->name);
- X perror ("unlink");
- X }
- X }
- X}
- X
- X/*
- X * buffer management
- X */
- struct buffer {
- X char *ptr; /* points to current append point */
- X int size; /* how big is the buffer now? */
- X char text[1]; /* (extensible) array of bytes in the buffer */
- X};
- X
- X/*
- X * Create an empty buffer
- X */
- X
- struct buffer *
- create_buffer (initial_size)
- unsigned int initial_size;
- X{
- X struct buffer *buf;
- X
- X if (initial_size <= 0)
- X initial_size = 1000;
- X if ((buf = (struct buffer *)
- X calloc (1, sizeof (struct buffer) + initial_size - 1)) == NULL)
- X return NULL;
- X buf->ptr = &(buf->text[0]);
- X buf->size = initial_size;
- X return buf;
- X}
- X
- X/*
- X * Ensure there is enough room in the buffer for "more" more bytes
- X */
- struct buffer *
- enlarge_buffer (buf, more)
- struct buffer *buf;
- int more;
- X{
- X int offset = buf->ptr - &(buf->text[0]);
- X int spaceleft = buf->size - offset;
- X
- X if (more > spaceleft) {
- X int newsize = sizeof (struct buffer) + (buf->size * 2) - 1;
- X buf = (struct buffer *) realloc ((char *) buf, newsize);
- X if (buf == NULL) {
- X perror ("enlarge_buffer(): realloc failed");
- X return NULL;
- X }
- X buf->ptr = &(buf->text[0]) + offset;
- X buf->size = newsize;
- X }
- X return buf;
- X}
- X
- X/*
- X * Append up to max_size bytes from an open file to buffer
- X */
- X
- struct buffer *
- read_file_into_buffer (buf, fd, max_size)
- struct buffer *buf;
- int fd;
- unsigned max_size;
- X{
- X int real_size = 0;
- X
- X while (max_size > 0) {
- X int foo = min (max_size, max_net_read);
- X if ((buf = enlarge_buffer (buf, foo)) == NULL)
- X return NULL;
- X if ((foo = read (fd, buf->ptr, foo)) < 0)
- X return NULL;
- X if (foo == 0)
- X break;
- X buf->ptr += foo;
- X max_size -= foo;
- X real_size += foo;
- X }
- X return buf;
- X}
- X
- X/*
- X * Append a NUL-terminated string to the buffer
- X */
- X
- struct buffer *
- append_string_to_buffer (buf, string, length)
- struct buffer *buf;
- char *string;
- int length;
- X{
- X if ((buf = enlarge_buffer (buf, length)) == NULL) {
- X fprintf (stderr, "lpr: file too big to fit in memory\n");
- X exit (EXIT_FAIL);
- X }
- X strncpy (buf->ptr, string, length);
- X buf->ptr += length;
- X return buf;
- X}
- X
- X/*
- X * Write out the entire contents of buffer to the file fd.
- X */
- X
- int
- send_file_from_buffer (fd, buf)
- int fd; struct buffer *buf;
- X{
- X char *wptr = buf->text;
- X while (wptr < buf->ptr) {
- X unsigned int foo = min (buf->ptr - wptr, max_net_write);
- X if ((foo = y_write (fd, wptr, foo)) < 0)
- X return EOF;
- X wptr += foo;
- X }
- X return 0;
- X}
- X
- X/*
- X * free up a buffer
- X */
- X
- void
- free_buffer (buf)
- struct buffer *buf;
- X{
- X if (buf)
- X cfree (buf);
- X}
- X
- int
- buffer_size (buf)
- struct buffer *buf;
- X{
- X if (buf)
- X return (buf->ptr - buf->text);
- X return EOF;
- X}
- X
- X/*
- X * Look at a file buffer and guess what kind of file it is. This is called
- X * when we aren't given an explicit file type option.
- X */
- X
- char
- guess_file_type (buf, fname)
- struct buffer *buf; char *fname;
- X{
- X char *ptr = buf->text;
- X if (ptr[0] == '%' && ptr[1] == '!')
- X return 'f'; /* print PostScript as plain file */
- X if (ptr[0] == '\367' && ptr[1] == 2) {
- X fprintf (stderr, "lpr: %s is a TeX .dvi file, assuming -d\n", fname);
- X return 'd'; /* TeX .dvi file */
- X }
- X if (ptr[0] == '\100' && ptr[1] == '\357') {
- X fprintf (stderr, "lpr: %s is a C/A/T troff output file, assuming -t\n",
- X fname);
- X return 't'; /* C/A/T troff file */
- X }
- X return 'f'; /* default file type is plain file */
- X}
- X
- int
- check_for_bogus_file (buf, type, filename)
- struct buffer *buf; char type; char *filename;
- X{
- X char *ptr = buf->text;
- X
- X if (buf->ptr == buf->text) {
- X fprintf (stderr, "lpr: skipping zero-length file %s\n", filename);
- X return EOF;
- X }
- X
- X if (ptr[0] == '\037' && ptr[1] == '\235') {
- X fprintf (stderr, "lpr: %s is a compressed file -- ignoring it\n",
- X filename);
- X return EOF;
- X }
- X if (type == 'd') {
- X if (ptr[0] == '\367' && ptr[1] == '\002') {
- X /* sometimes .dvi files have trailing NULs when they
- X shouldn't have. Remove these from the buffer and
- X check that the .dvi file ends with a \337 byte. */
- X if (buf->ptr[-1] == '\0') {
- X while (buf->ptr[-1] == '\0')
- X --(buf->ptr);
- X }
- X if (buf->ptr[-1] == '\337')
- X return 0;
- X }
- X fprintf (stderr, "lpr: %s is not a valid .dvi file", filename);
- X return EOF;
- X }
- X if (memcmp (ptr, "!<arch>\n", 8) == 0) {
- X fprintf (stderr, "lpr: %s is a UNIX library archive -- ignoring it",
- X filename);
- X return EOF;
- X }
- X return 0;
- X}
- X
- X
- X/*
- X * Send a command to the remote server and wait for a response. Return
- X * the first byte of the response, or EOF on error.
- X */
- X
- int
- send_command (fd, buf, size)
- int fd; char *buf; unsigned int size;
- X{
- X char x[1];
- X if (x_write (fd, buf, size) != size)
- X return EOF;
- X if (x_read (fd, x, 1) != 1)
- X return EOF;
- X return *x;
- X}
- X
- X
- X/*
- X * structure used to keep track of print jobs
- X */
- struct job {
- X int jobid; /* integer job id 1-999 */
- X int fd; /* fd of lpd socket */
- X int control_file_number; /* current file number */
- X int data_file_number; /* data_file_number */
- X struct buffer *cfile; /* buffer to build control file */
- X};
- X
- X/*
- X * add a record to a control file
- X */
- void
- control (job, cmd, arg)
- struct job *job; char cmd; char *arg;
- X{
- X char buf[512];
- X sprintf (buf, "%c%s\n", cmd, arg);
- X job->cfile = append_string_to_buffer (job->cfile, buf, strlen (buf));
- X}
- X
- X
- X/*
- X * create a print job. Return a job ptr on success or NULL on error.
- X */
- struct job *
- open_job (queuename)
- char *queuename;
- X{
- X struct job *job;
- X char buf[512];
- X char x;
- X
- X if ((job = (struct job *) calloc (1, sizeof (struct job))) == NULL)
- X return NULL;
- X /*
- X * generate a job #. Really, this should be maintained on a
- X * per-(host,queue) basis, so we won't have naming conflicts.
- X * for now, we just generate something pseudo-random.
- X */
- X job->jobid = time (0) % 1000;
- X job->fd = open_lpd (lpd_server);
- X if (job->fd < 0) {
- X free (job);
- X return NULL;
- X }
- X
- X sprintf (buf, "\2%s\n", queuename);
- X if ((x = send_command (job->fd, buf, strlen (buf))) != 0) {
- X if (isprint (x)) {
- X int foo;
- X *buf = x;
- X foo = x_read (job->fd, buf+1, sizeof(buf)-1);
- X fprintf (stderr,
- X "lpr: server %s refused job with message:\n",
- X lpd_server);
- X fprintf (stderr, "%.*s", foo+1, buf);
- X }
- X else {
- X fprintf (stderr,
- X "lpr: server %s refused job for printer %s\n",
- X lpd_server, queuename);
- X }
- X close (job->fd);
- X free (job);
- X return NULL;
- X }
- X
- X job->control_file_number = 0;
- X job->data_file_number = 0;
- X job->cfile = create_buffer (1000);
- X
- X control (job, 'H', hostname);
- X control (job, 'P', username);
- X if (hflag == 0) {
- X control (job, 'J', jobtitle);
- X control (job, 'C', jobclass);
- X }
- X control (job, 'L', username);
- X if (title)
- X control (job, 'T', title);
- X if (mflag)
- X control (job, 'M', email_address);
- X return job;
- X}
- X
- void
- concoct_file_name (c, job, str)
- char c; struct job *job; char *str;
- X{
- X int x = c == 'd' ? job->data_file_number++ : job->control_file_number++;
- X sprintf (str, "%cf%c%03d%s", c,
- X "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"[x],
- X job->jobid, hostname);
- X}
- X
- X/*
- X * Send a file to be printed. Return 1 on success and 0 on error.
- X * (i.e. # of files sent).
- X * print diagnostic messages to stderr as necessary
- X * If file == NULL, print standard input
- X */
- int
- send_print_file (job, file, file_type)
- struct job *job; char *file; char file_type;
- X{
- X int estimated_size; /* how big we think the file is */
- X int max_size; /* max size to print */
- X int real_size;
- X int fd = EOF; /* fd of file */
- X struct buffer *dfile = NULL; /* buffer to read file into */
- X char *reason = NULL; /* reason file xfer failed */
- X char data_file_name[512]; /* name of temporary data file */
- X char buf[512];
- X int x;
- X int i;
- X
- X /*
- X * open the file and find out how big it is
- X * estimated_size is used to determine how much space to allocate.
- X * max_size is used to decide how much to read in. Under VMS
- X * we don't ever want to read too much, because we might get
- X * unwanted garbage at the end of a fixed-length record file.
- X */
- X if (file) {
- X struct stat sbuf;
- X if (stat (file, &sbuf) < 0) {
- X perror (file);
- X return 0;
- X }
- X max_size = estimated_size = sbuf.st_size;
- X if ((fd = open (file, 0)) < 0) {
- X perror (file);
- X return 0;
- X }
- X }
- X else {
- X struct stat sbuf;
- X file = "standard input"; /* for page headers, error messages */
- X estimated_size = 64000;
- X max_size = 5*1024*1024; /* 5 megabytes */
- X fd = 0;
- X#ifdef unix
- X /*
- X * UNIX-specific performance optimization:
- X * If standard input is an ordinary file, get size estimate
- X * with fstat()
- X */
- X if (fstat (fd, &sbuf) < 0) {
- X if ((sbuf.st_mode & S_IFMT) == S_IFREG)
- X estimated_size = sbuf.st_size;
- X }
- X#endif
- X }
- X
- X /*
- X * create a buffer and read the file into it.
- X */
- X concoct_file_name ('d', job, data_file_name);
- X if ((dfile = create_buffer (estimated_size)) == NULL) {
- X reason = "file too big to fit in memory";
- X goto abort;
- X }
- X if ((dfile = read_file_into_buffer (dfile, fd, max_size)) == NULL) {
- X reason = "error reading file";
- X goto abort;
- X }
- X
- X /*
- X * file transfer successful. Add this file to the print job,
- X * clean up, and return.
- X */
- X if (file_type == '?')
- X file_type = guess_file_type (dfile, file);
- X /*
- X * check for bogus file formats. Refuse to print anything that
- X * is obviously bogus.
- X */
- X if (check_for_bogus_file (dfile, file_type, file))
- X goto okay;
- X
- X /*
- X * transfer the file to the server, with error checking
- X */
- X sprintf (buf, "\3%d %s\n", buffer_size(dfile), data_file_name);
- X if ((x = send_command (job->fd, buf, strlen (buf))) != 0) {
- X switch (x) {
- X case 1:
- X break;
- X case 2:
- X reason = "not enough disk space on server (or file is too large)";
- X break;
- X case EOF:
- X reason = "connection to printer server broken";
- X break;
- X default:
- X if (isprint (x)) {
- X *buf = x;
- X x = x_read (job->fd, buf + 1, sizeof (buf) - 1);
- X buf[x+1] = '\0';
- X reason = buf;
- X }
- X }
- X goto abort;
- X }
- X if (send_file_from_buffer (job->fd, dfile) != 0)
- X goto abort;
- X if (send_command (job->fd, "", 1) < 0)
- X goto abort;
- X
- X if (file_type == 'p' && !title)
- X control (job, 'P', file);
- X for (i = 0; i < num_copies; ++i)
- X control (job, file_type, data_file_name);
- X control (job, 'U', data_file_name);
- X control (job, 'N', file);
- X okay:
- X free_buffer (dfile);
- X close (fd);
- X return 1;
- X
- X
- X /*
- X * file transfer failed. print error message and clean up
- X */
- X abort:
- X fprintf (stderr, "lpr: unable to send file %s to print server %s\n",
- X file, lpd_server);
- X if (reason)
- X fprintf (stderr, "reason: %s\n", reason);
- X if (dfile)
- X free_buffer (dfile);
- X if (fd > 0)
- X close (fd);
- X return 0;
- X}
- X
- X/*
- X * send the control file. Return 0 on success, nonzero on error.
- X */
- send_control_file (job)
- struct job *job;
- X{
- X char buf[512];
- X char control_file_name[512];
- X
- X concoct_file_name ('c', job, control_file_name);
- X sprintf (buf, "\2%d %s\n", job->cfile->ptr - job->cfile->text,
- X control_file_name);
- X if (send_command (job->fd, buf, strlen (buf)) < 0)
- X return 1;
- X if (send_file_from_buffer (job->fd, job->cfile) != 0)
- X return 1;
- X if (send_command (job->fd, "", 1) < 0)
- X return 1;
- X return 0;
- X}
- X
- X/*
- X * close a job normally and delete its resources
- X */
- int
- close_job (job)
- struct job *job;
- X{
- X int x;
- X if (job == NULL)
- X return EOF;
- X x = send_control_file (job);
- X if (job->cfile)
- X free_buffer (job->cfile);
- X close (job->fd);
- X cfree (job);
- X return x;
- X}
- X
- X/*
- X * abort a job and delete its resources
- X */
- void
- abort_job (job)
- struct job *job;
- X{
- X if (job == NULL)
- X return;
- X x_write (job->fd, "\1\n", 2);
- X close (job->fd);
- X if (job->cfile)
- X free_buffer (job->cfile);
- X cfree (job);
- X}
- X
- X
- char *
- get_lpd_server ()
- X{
- X FILE *fp;
- X static char *buf[512];
- X
- X if ((fp = fopen ("/etc/LPD_SERVER", "r")) == (FILE *) NULL)
- X return NULL;
- X if (fscanf (fp, " %511s", buf) != 1)
- X return NULL;
- X return (char *) buf;
- X}
- X
- X
- X/*
- X * Dummy main program exists to find out what name we are being called
- X * by (under UNIX, anyway) and act appropriately. This program has
- X * multiple personalities...
- X */
- X
- main (argc, argv)
- int argc; char **argv;
- X{
- X#ifdef unix
- X char *progname = NULL;
- X char *strrchr ();
- X#endif
- X char *p;
- X
- X /*
- X * inherit some defaults from the environment
- X */
- X
- X printer = getenv ("PRINTER");
- X if (printer == NULL)
- X printer = "lp";
- X lpd_server = getenv ("LPD_SERVER");
- X if (lpd_server == NULL)
- X lpd_server = get_lpd_server ();
- X
- X sysdep ();
- X
- X#ifdef unix
- X /*
- X * look at the last component of the name we were invoked with
- X * and determine how to behave.
- X */
- X progname = strrchr (argv[0], '/');
- X if (progname == NULL)
- X progname = argv[0];
- X else
- X progname++;
- X
- X if (strcmp (progname, "lpq") == 0)
- X return (lpq (argc, argv));
- X else if (strcmp (progname, "lprm") == 0)
- X return (lprm (argc, argv));
- X#endif
- X
- X /*
- X * if first argument is -remove or -delete, behave as lprm
- X * if first argumetn is -showqueue, behave as lpq
- X */
- X
- X if (argc > 1) {
- X if (strcmp (argv[1], "-remove") == 0)
- X return (lprm (argc-1, argv+1));
- X else if (strcmp (argv[1], "-delete") == 0)
- X return (lprm (argc-1, argv+1));
- X else if (strcmp (argv[1], "-showqueue") == 0)
- X return (lpq (argc-1, argv+1));
- X }
- X
- X return (lpr (argc, argv));
- X}
- X
- X/*
- X * queue one or more files for printing
- X */
- X
- lpr (argc, argv)
- int argc; char **argv;
- X{
- X struct job *job = NULL;
- X int i;
- X int file_args = 0;
- X int files_printed = 0;
- X
- X jobclass = hostname;
- X jobtitle = NULL;
- X
- X for (i = 1; i < argc; ++i) {
- X if (*argv[i] == '-')
- X i += option (argv[i], argv[i+1]);
- X else {
- X if (!jobtitle) {
- X char *ptr = strrchr (argv[i], '/');
- X jobtitle = ptr ? ptr + 1 : argv[i];
- X }
- X if (job == NULL && (job = open_job (printer)) == NULL)
- X exit (EXIT_FAIL);
- X file_args++;
- X if (send_print_file (job, argv[i], file_type)) {
- X files_printed++;
- X if (rflag)
- X mark_for_delete (argv[i]);
- X }
- X }
- X }
- X if (file_args == 0) {
- X if (!jobtitle)
- X jobtitle = "stdin";
- X if ((job = open_job (printer)) == NULL)
- X exit (EXIT_FAIL);
- X files_printed += send_print_file (job, 0, file_type);
- X }
- X if (files_printed > 0) {
- X if (close_job (job)) {
- X delete_marked_files ();
- X exit (EXIT_OK);
- X }
- X else
- X exit (EXIT_FAIL);
- X }
- X else
- X exit (EXIT_FAIL);
- X exit (EXIT_OK);
- X}
- X
- X/*
- X * print contents of printer queue
- X * "lpq -l" prints in long format
- X */
- X
- lpq (argc, argv)
- int argc; char **argv;
- X{
- X int i;
- X char buf[512];
- X int fd;
- X int x;
- X
- X for (i = 1; i < argc ; ++i) {
- X if (*argv[i] == '-')
- X i += option (argv[i], argv[i+1]);
- X else
- X break;
- X }
- X
- X if ((fd = open_lpd (lpd_server)) < 0)
- X exit (EXIT_FAIL);
- X
- X if (lflag)
- X sprintf (buf, "\004%s", printer);
- X else
- X sprintf (buf, "\003%s", printer);
- X
- X for (; i < argc; ++i) {
- X strcat (buf, " ");
- X strcat (buf, argv[i]);
- X }
- X
- X strcat (buf, "\n");
- X if (x_write (fd, buf, strlen (buf)) != 0) {
- X while ((x = x_read (fd, buf, sizeof buf)) > 0)
- X fwrite (buf, sizeof (char), x, stdout);
- X }
- X close (fd);
- X return 0;
- X}
- X
- X/*
- X * remove jobs from queue
- X */
- X
- lprm (argc, argv)
- int argc; char **argv;
- X{
- X int fd;
- X int i;
- X char buf[512];
- X int x;
- X int response_length = 0;
- X int remove_all = 0;
- X
- X for (i = 1; i < argc; ++i) {
- X if (strcmp (argv[i], "-") == 0)
- X remove_all++;
- X else if (*argv[i] == '-')
- X i += option (argv[i], argv[i+1]);
- X else
- X break;
- X }
- X
- X if ((fd = open_lpd (lpd_server)) < 0)
- X exit (EXIT_FAIL);
- X
- X /*
- X * If user asks to remove all queued files with "lprm -",
- X * need to check to see if user is privileged to do so.
- X * Allow root to remove all queued files, but any other
- X * user will just remove his/her own queued files.
- X * (remote server will only delete files queued by this system)
- X *
- X * "-all" is a magic user name which means delete all
- X * entries from this system.
- X */
- X if (remove_all) {
- X#ifdef unix
- X if (strcmp (username, "root") == 0)
- X sprintf (buf, "\005%s %s", printer, "-all");
- X else
- X sprintf (buf, "\005%s %s %s", printer, username, username);
- X#else
- X sprintf (buf, "\005%s %s %s", printer, username, username);
- X#endif
- X }
- X else {
- X sprintf (buf, "\005%s %s", printer, username);
- X }
- X
- X for (; i < argc; ++i) {
- X strcat (buf, " ");
- X strcat (buf, argv[i]);
- X }
- X strcat (buf, "\n");
- X if (x_write (fd, buf, strlen (buf)) != 0) {
- X while ((x = x_read (fd, buf, sizeof buf)) > 0) {
- X fwrite (buf, sizeof (char), x, stdout);
- X response_length += x;
- X }
- X }
- X close (fd);
- X
- X /* If response_length is zero, assume the remove command failed.
- X Otherwise we should have received some confirmation message */
- X
- X if (response_length == 0)
- X return 1;
- X return 0;
- X}
- END_OF_FILE
- if test 25058 -ne `wc -c <'lpr.c'`; then
- echo shar: \"'lpr.c'\" unpacked with wrong size!
- fi
- # end of 'lpr.c'
- fi
- if test -f 'config.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'config.h'\"
- else
- echo shar: Extracting \"'config.h'\" \(1220 characters\)
- sed "s/^X//" >'config.h' <<'END_OF_FILE'
- X/*
- X * The printer server can be told to send email on job completion.
- X * By default, this is sent to user@domain, where domain is the
- X * fully-qualified Internet domain name (as returned by gethostbyname()).
- X * If this will not work (perhaps because the host that is running this
- X * version of lpr cannot receive mail), define MAKE_EMAIL_ADDRESS here
- X * as a macro that will concoct an appropriate address. Examples follow:
- X *
- X *
- X * for a VMS machine that can receive DECnet mail, and a UNIX lpd server
- X * that understands mail sent to user@node.DECnet, do:
- X *
- X * #define MAKE_EMAIL_ADDRESS(buf,user,dom) \
- X sprintf (buf, "%s@%s.DECnet", user, getenv ("SYS$NODE"))
- X *
- X *
- X * for a VMS machine that can receive DECnet mail, and an lpd server
- X * that can send mail to node::user, use:
- X *
- X * #define MAKE_EMAIL_ADDRESS(buf,user,dom) \
- X * sprintf (buf, "%s::%s", getenv ("SYS$NODE"), user)
- X *
- X * Or you can concoct your own. For instance, we at UTK have an Internet
- X * domain dnet.utk.edu that maps node.dnet.utk.edu to the appropriate
- X * DECnet node for the purposes of email. So we use:
- X *
- X * #define MAKE_EMAIL_ADDRESS(buf,user,dom) \
- X * sprintf (buf, "%s@%s.dnet.utk.edu", user, getenv ("SYS$NODE"))
- X */
- END_OF_FILE
- if test 1220 -ne `wc -c <'config.h'`; then
- echo shar: \"'config.h'\" unpacked with wrong size!
- fi
- # end of 'config.h'
- fi
- if test -f 'common.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'common.h'\"
- else
- echo shar: Extracting \"'common.h'\" \(498 characters\)
- sed "s/^X//" >'common.h' <<'END_OF_FILE'
- X#ifdef MAIN_PROGRAM
- X#define STORAGE_CLASS
- X#else
- X#define STORAGE_CLASS extern
- X#endif
- X
- STORAGE_CLASS char hostname[512]; /* name of this host */
- STORAGE_CLASS char username[100]; /* name of user submitting job */
- STORAGE_CLASS char email_address[512]; /* submitting user's email address */
- STORAGE_CLASS int debug; /* true if we want debugging output */
- STORAGE_CLASS int max_net_read; /* max # of bytes to read at a time */
- STORAGE_CLASS int max_net_write; /* max # of bytes to write at a time */
- END_OF_FILE
- if test 498 -ne `wc -c <'common.h'`; then
- echo shar: \"'common.h'\" unpacked with wrong size!
- fi
- # end of 'common.h'
- fi
- if test -f 'patchlevel.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'patchlevel.h'\"
- else
- echo shar: Extracting \"'patchlevel.h'\" \(21 characters\)
- sed "s/^X//" >'patchlevel.h' <<'END_OF_FILE'
- X#define PATCHLEVEL 4
- END_OF_FILE
- if test 21 -ne `wc -c <'patchlevel.h'`; then
- echo shar: \"'patchlevel.h'\" unpacked with wrong size!
- fi
- # end of 'patchlevel.h'
- fi
- if test -f 'unix-tcp.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'unix-tcp.c'\"
- else
- echo shar: Extracting \"'unix-tcp.c'\" \(4522 characters\)
- sed "s/^X//" >'unix-tcp.c' <<'END_OF_FILE'
- X/*
- X * lpr interface for UNIX (i.e. BSD-ish) tcp
- X */
- X
- X#include "common.h"
- X#include "config.h"
- X#include <stdio.h>
- X#include <ctype.h>
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#include <pwd.h>
- X#include <netdb.h>
- X#include <sys/socket.h>
- X#include <errno.h>
- X#include <netinet/in.h>
- X
- X#ifndef MAKE_EMAIL_ADDRESS
- X#define MAKE_EMAIL_ADDRESS(buf,user,dom) sprintf (buf, "%s@%s", user, dom)
- X#endif
- X
- X
- struct hostent *
- gethostbynameoraddr (hostname)
- char *hostname;
- X{
- X if (isdigit (*hostname)) {
- X static struct hostent x;
- X static char *alias_list[1];
- X static unsigned long *addr_list[2];
- X static unsigned long ip_address;
- X
- X ip_address = inet_addr (hostname);
- X
- X addr_list[0] = &ip_address;
- X addr_list[1] = NULL;
- X alias_list[0] = NULL;
- X
- X x.h_name = hostname;
- X x.h_aliases = alias_list;
- X x.h_addrtype = AF_INET;
- X x.h_length = sizeof (unsigned long);
- X x.h_addr_list = (char **) addr_list;
- X return &x;
- X }
- X return gethostbyname (hostname);
- X}
- X
- void sysdep()
- X{
- X struct passwd *pwd;
- X char *p;
- X struct hostent *hp;
- X char *getenv ();
- X
- X gethostname (hostname, sizeof hostname);
- X
- X if (pwd = getpwuid (getuid ()))
- X strcpy (username, pwd->pw_name);
- X else {
- X fprintf (stderr, "lpr: system problem: can't get your username!\n");
- X exit (1);
- X }
- X endpwent ();
- X
- X hp = gethostbyname (hostname);
- X MAKE_EMAIL_ADDRESS(email_address, username, hp ? hp->h_name : hostname);
- X}
- X
- X
- X/*
- X * Allocate a socket and bind it to a local privileged port
- X * We have to be running set-uid to root to do this.
- X */
- X
- int
- get_priv_tcp_socket ()
- X{
- X int fd;
- X int port;
- X struct sockaddr_in s;
- X
- X if ((fd = socket (AF_INET, SOCK_STREAM, 0)) == EOF) {
- X perror ("socket");
- X return EOF;
- X }
- X for (port = IPPORT_RESERVED-1; port > IPPORT_RESERVED / 2; port--) {
- X extern int errno;
- X s.sin_family = AF_INET;
- X s.sin_addr.s_addr = INADDR_ANY;
- X s.sin_port = htons (port);
- X if (bind (fd, (struct sockaddr *) &s, sizeof (s)) == 0)
- X return fd;
- X if (errno == EACCES) {
- X fprintf (stderr, "lpr warning: bind: cannot bind to privileged port\n");
- X return fd;
- X }
- X }
- X close (fd);
- X return EOF;
- X}
- X
- X/*
- X * Open a TCP connection to an lpd-server.
- X * This requires that this program be run set-uid to root in order to be able
- X * to bind a socket to a privileged port.
- X */
- X
- int
- open_lpd (server)
- char *server;
- X{
- X int fd;
- X int i;
- X int last_connect_failed;
- X struct hostent *hp;
- X struct servent *sp;
- X struct sockaddr_in s;
- X
- X if (server == NULL || *server == '\0') {
- X fprintf (stderr, "lpr: no server host was specified.\n");
- X fprintf (stderr, " Supply one with the -S option, or\n");
- X fprintf (stderr, " by setting the LPD_SERVER environment variable\n");
- X return EOF;
- X }
- X if ((hp = gethostbynameoraddr (server)) == NULL) {
- X fprintf (stderr, "lpr: can't find network address for %s\n",
- X server);
- X fflush (stderr);
- X return EOF;
- X }
- X
- X s.sin_family = AF_INET;
- X if ((sp = getservbyname ("printer", "tcp")) == NULL)
- X s.sin_port = htons (515);
- X else
- X s.sin_port = sp->s_port;
- X
- X /*
- X * On some systems h_addr is a macro that is defined to be h_addr_list[0]
- X * On other (ancient) systems, h_addr is a member of the hostent structure.
- X * So if h_addr is defined as a macro, then we must have the list...
- X */
- X
- X#ifdef h_addr
- X for (i = 0; hp->h_addr_list[i] ; ++i) {
- X fd = get_priv_tcp_socket ();
- X disable_special_privileges ();
- X if (fd < 0)
- X return EOF;
- X bcopy (hp->h_addr_list[i], &s.sin_addr, sizeof (s.sin_addr));
- X if (debug)
- X fprintf (stderr, "Trying %s...", inet_ntoa (s.sin_addr));
- X last_connect_failed = 0; /* "I'm ashamed of this." - SMK */
- X if (connect (fd, &s, sizeof s) == 0) {
- X if (debug)
- X fprintf (stderr, "open\n");
- X break;
- X }
- X else {
- X close (fd); /* reuse fd */
- X if (debug)
- X perror ("");
- X last_connect_failed = 1;
- X }
- X }
- X if (last_connect_failed) {
- X perror ("connect");
- X return EOF;
- X }
- X#else
- X fd = get_priv_tcp_socket ();
- X disable_special_privileges ();
- X if (fd < 0)
- X return EOF;
- X bcopy (hp->h_addr, (char *) &s.sin_addr, sizeof(s.sin_addr));
- X if (connect (fd, &s, sizeof s) < 0) {
- X perror ("connect");
- X close (fd);
- X return EOF;
- X }
- X#endif
- X
- X max_net_read = max_net_write = 32767;
- X return fd;
- X}
- X
- X/*
- X * Turn off set-uid privileges.
- X * We have to be running set-uid to root in order to bind to a privileged
- X * port. In order to minimize the security risk, this function is called
- X * from open_job() immediately after open_lpd() returns.
- X */
- X
- disable_special_privileges ()
- X{
- X setuid (getuid ());
- X}
- END_OF_FILE
- if test 4522 -ne `wc -c <'unix-tcp.c'`; then
- echo shar: \"'unix-tcp.c'\" unpacked with wrong size!
- fi
- # end of 'unix-tcp.c'
- fi
- if test -f 'Makefile' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'Makefile'\"
- else
- echo shar: Extracting \"'Makefile'\" \(3332 characters\)
- sed "s/^X//" >'Makefile' <<'END_OF_FILE'
- X# fix SysV brain-damage
- SHELL=/bin/sh
- X#
- DEFAULT_SERVER=
- X#
- X# pick a back-end driver from one of the following:
- X#
- DRIVER=unix-tcp.o # UNIX w/BSD-style sockets
- X# (others to follow...maybe)
- X#
- X# This program was originally developed with GCC, but it doesn't always
- X# use the same calling sequence as the system libraries (particularly
- X# inet_ntoa()), so I don't use it for this anymore.
- X# If your C compiler runs on UNIX, but doesn't define "unix" as a macro,
- X# define it on the CFLAGS line with -Dunix
- X# Don't get nervous, I always compile with -g.
- X#
- X#CC=gcc -ansi -g -Dunix
- CFLAGS=-g -Dunix
- X#
- X# nroff (or some facsimile thereof) is used to format the man pages.
- X# I used groff because that way I don't end up with man pages that say
- X# "SunOS" or "Ultrix" or some such.
- X#
- X#NROFF=nroff
- NROFF=groff -Tascii
- X#
- X# Set BINDIR to the directory where the program will be installed.
- X# This doesn't affect the compilation, so you can set this after
- X# compiling.
- X#
- BINDIR=/usr/local/bin
- X#
- X# Set GWDIR to where the (optional) dnet-to-tcp lpr gateway will
- X# be installed. This doesn't affect compilation either.
- X#
- GWDIR=/usr/sunlink/dni
- X#
- X# List of sources, for bundling together in a package
- X#
- SRCS=lpr.c config.h common.h patchlevel.h \
- X unix-tcp.c Makefile \
- X vms-ucx-tcp.c vms-decnet.c vms-win-tcp.c descrip.mms \
- X dnet-lpd-gw.c \
- X lpr.man lpr.cat
- X#
- X# other stuff that goes with the package
- X#
- PKG=BLURB README MANIFEST LICENSE ChangeLog $(SRCS)
- X
- X#
- X# The -lsocket stuff is an attempt to get this to work on machines
- X# that have a BSD socket library built on top of STREAMS-based tcp
- X# without having to have a hairy configuration program just to compile
- X# this.
- X#
- lpr: lpr.c config.h $(DRIVER)
- X -if [ -f /usr/lib/libsocket.a ] ; then \
- X $(CC) $(CFLAGS) -o lpr lpr.c $(DRIVER) -lsocket ; \
- X else \
- X $(CC) $(CFLAGS) -o lpr lpr.c $(DRIVER) ; \
- X fi
- X
- dnet-lpd-gw: dnet-lpd-gw.c unix-tcp.o
- X $(CC) $(CFLAGS) -o dnet-lpd-gw dnet-lpd-gw.c unix-tcp.o
- X
- X#
- X# preformatted man page, in case someone doesn't have nroff
- X#
- lpr.cat: lpr.man
- X $(NROFF) -man lpr.man > lpr.cat
- X
- X#
- X# The wierd "rm || mv" stuff is an attempt to work around SysV brain
- X# damage that won't let you rm a program that is running.
- X#
- install: lpr
- X cp lpr $(BINDIR)/lpr.new
- X chown root $(BINDIR)/lpr.new
- X chmod 4711 $(BINDIR)/lpr.new
- X -rm $(BINDIR)/lpr || mv $(BINDIR)/lpr $(BINDIR)/lpr.old
- X mv $(BINDIR)/lpr.new $(BINDIR)/lpr
- X -rm $(BINDIR)/lprm || mv $(BINDIR)/lprm $(BINDIR)/lprm.old
- X ln $(BINDIR)/lpr $(BINDIR)/lprm
- X -rm $(BINDIR)/lpq || mv $(BINDIR)/lpq $(BINDIR)/lpq.old
- X ln $(BINDIR)/lpr $(BINDIR)/lpq
- X
- install-gw: dnet-lpd-gw
- X rm -f $(GWDIR)/dnet-lpd-gw
- X cp dnet-lpd-gw $(GWDIR)
- X chown root $(GWDIR)/dnet-lpd-gw
- X chmod 4711 $(GWDIR)/dnet-lpd-gw
- X
- clean:
- X rm -f lpr dnet-lpd-gw *.o
- X
- X#
- X# various packaging routines.
- X#
- port-lpr.vms: $(PKG)
- X /bin/true > port-lpr.vms
- X for i in $(PKG) ; do \
- X echo '$$ write sys$$output "creating' $$i'"' ; \
- X echo '$$ CREATE' $$i ; \
- X cat $$i ; \
- X done >> port-lpr.vms
- X echo '$$ exit' >> port-lpr.vms
- X
- port-lpr.tar: $(PKG)
- X tar cf port-lpr.tar $(PKG)
- X
- port-lpr.tar.Z.uu: $(PKG)
- X tar cf - $(PKG) | compress | uuencode port-lpr.tar.Z > port-lpr.tar.Z.uu
- X
- port-lpr.uushar: $(PKG)
- X for i in $(PKG) ; do uuencode $$i < $$i ; done > port-lpr.uushar
- X
- port-lpr.shar: $(PKG)
- X shar $(PKG) > port-lpr.shar
- X
- print:
- X enscript -2r `ls $(SRCS) | grep '.*\.[ch]'`
- END_OF_FILE
- if test 3332 -ne `wc -c <'Makefile'`; then
- echo shar: \"'Makefile'\" unpacked with wrong size!
- fi
- # end of 'Makefile'
- fi
- if test -f 'vms-ucx-tcp.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'vms-ucx-tcp.c'\"
- else
- echo shar: Extracting \"'vms-ucx-tcp.c'\" \(8256 characters\)
- sed "s/^X//" >'vms-ucx-tcp.c' <<'END_OF_FILE'
- X/*
- X * lpr interface for VAX/VMS UCX TCP
- X */
- X
- X#include "common.h"
- X#include "config.h"
- X#include <stdio.h>
- X#include <ctype.h>
- X#include <types.h>
- X#include <stat.h>
- X#include <netdb.h>
- X#include <socket.h>
- X#include <errno.h>
- X#include <in.h>
- X#include <prvdef.h>
- X#include <jpidef.h>
- X#include <ssdef.h>
- X#include <lnmdef.h>
- X
- struct item_list {
- X unsigned short buffer_length;
- X unsigned short item_code;
- X char *buffer_address;
- X char *length_address;
- X};
- X
- struct descrip {
- X int length;
- X char *ptr;
- X};
- X
- X/*
- X * Translate a VAX/VMS logical name, given the name we want to translate
- X * and the table name we want to search with.
- X */
- X
- int
- translate_logical_name (table, name, buf, size)
- char *table; char *name; char *buf; int size;
- X{
- X struct descrip table_d;
- X struct descrip name_d;
- X struct item_list item_list[2];
- X int foo;
- X int status;
- X
- X table_d.length = strlen (table);
- X table_d.ptr = table;
- X name_d.length = strlen (name);
- X name_d.ptr = name;
- X item_list[0].buffer_length = size - 1;
- X item_list[0].item_code = LNM$_STRING;
- X item_list[0].buffer_address = buf;
- X item_list[0].length_address = &foo;
- X item_list[1].buffer_length = 0;
- X item_list[1].item_code = 0;
- X item_list[1].buffer_address = 0;
- X item_list[1].length_address = 0;
- X status = SYS$TRNLNM (0, &table_d, &name_d, 0, item_list);
- X if ((status & 01) != 01)
- X lib$signal (status);
- X if (foo >= 0 && foo < size)
- X buf[foo] = '\0';
- X return ((status & 01) ? 0 : EOF);
- X}
- X
- X/*
- X * Determine the DECnet node name by translating the system logical name
- X * SYS$NODE. We use this function rather than the getenv() function,
- X * just to make sure the user doesn't define his/her own SYS$NODE variable
- X * and pretend he/she is submitting the print job from somewhere else.
- X */
- X
- int
- get_decnet_node_name (buf, size)
- char *buf; int size;
- X{
- X
- X if (!translate_logical_name ("LNM$SYSTEM_TABLE", "SYS$NODE", buf, size)) {
- X char *p;
- X while ((p = strrchr (buf, ':')))
- X *p = '\0';
- X return 0;
- X }
- X return EOF;
- X}
- X
- X#ifndef MAKE_EMAIL_ADDRESS
- X#define MAKE_EMAIL_ADDRESS(buf,user,dom) sprintf (buf, "%s@%s", user, dom)
- X#endif
- X
- struct hostent *
- gethostbynameoraddr (hostname)
- char *hostname;
- X{
- X if (isdigit (*hostname)) {
- X static struct hostent x;
- X static char *alias_list[1];
- X static unsigned long *addr_list[2];
- X static unsigned long ip_address;
- X
- X ip_address = inet_addr (hostname);
- X
- X addr_list[0] = &ip_address;
- X addr_list[1] = NULL;
- X alias_list[0] = NULL;
- X
- X x.h_name = hostname;
- X x.h_aliases = alias_list;
- X x.h_addrtype = AF_INET;
- X x.h_length = sizeof (unsigned long);
- X x.h_addr_list = (char **) addr_list;
- X return &x;
- X }
- X return gethostbyname (hostname);
- X}
- X
- void
- sysdep()
- X{
- X struct passwd *pwd;
- X char *p;
- X struct hostent *hp;
- X char *getenv ();
- X char nodename[100];
- X
- X get_decnet_node_name (nodename, sizeof(nodename));
- X gethostname (hostname, sizeof hostname);
- X
- X /* get user name (will be in ALL CAPS - yikes!) */
- X cuserid (username);
- X
- X hp = gethostbyname (hostname);
- X MAKE_EMAIL_ADDRESS(email_address, username, hp ? hp->h_name : hostname);
- X
- X /* lower case host name and user name */
- X for (p = hostname; *p; ++p)
- X if (isupper (*p))
- X *p = tolower (*p);
- X
- X for (p = username; *p; ++p)
- X if (isupper (*p))
- X *p = tolower (*p);
- X}
- X
- X
- X/*
- X * Allocate a socket and bind it to a local privileged port
- X * We have to be running set-uid to root to do this.
- X */
- X
- int
- get_priv_tcp_socket ()
- X{
- X int fd;
- X int port;
- X struct sockaddr_in s;
- X
- X if ((fd = socket (AF_INET, SOCK_STREAM, 0)) == EOF) {
- X perror ("socket");
- X return EOF;
- X }
- X for (port = IPPORT_RESERVED-1; port > IPPORT_RESERVED / 2; port--) {
- X extern int errno;
- X s.sin_family = AF_INET;
- X s.sin_addr.s_addr = INADDR_ANY;
- X s.sin_port = htons (port);
- X if (bind (fd, (struct sockaddr *) &s, sizeof (s)) == 0)
- X return fd;
- X if (errno == EACCES) {
- X fprintf (stderr, "lpr warning: bind: cannot bind to privileged port\n");
- X return fd;
- X }
- X }
- X close (fd);
- X return EOF;
- X}
- X
- X/*
- X * Open a TCP connection to an lpd-server.
- X * This requires that this program be run set-uid to root in order to be able
- X * to bind a socket to a privileged port.
- X */
- X
- int
- open_lpd (server)
- char *server;
- X{
- X int fd;
- X int i;
- X int last_connect_failed;
- X struct hostent *hp;
- X struct servent *sp;
- X struct sockaddr_in s;
- X void bcopy ();
- X
- X if (server == NULL || *server == '\0') {
- X fprintf (stderr, "lpr: no server host was specified.\n");
- X fprintf (stderr, " Supply one with the -S option, or\n");
- X fprintf (stderr, " by defining the LPD_SERVER logical name\n");
- X return EOF;
- X }
- X if ((hp = gethostbynameoraddr (server)) == NULL) {
- X fprintf (stderr, "lpr: can't find network address for %s\n",
- X server);
- X fflush (stderr);
- X return EOF;
- X }
- X
- X s.sin_family = AF_INET;
- X#if 1
- X /* some bug in the VMS C optimizer seems to require this */
- X s.sin_port = htons (515);
- X#else
- X if ((sp = getservbyname ("printer", "tcp")) == NULL)
- X s.sin_port = htons (515);
- X else
- X s.sin_port = sp->s_port;
- X#endif
- X
- X /*
- X * On some systems h_addr is a macro that is defined to be h_addr_list[0]
- X * On other (ancient) systems, h_addr is a member of the hostent structure.
- X * So if h_addr is defined as a macro, then we must have the list...
- X */
- X
- X#ifdef h_addr
- X for (i = 0; hp->h_addr_list[i] ; ++i) {
- X fd = get_priv_tcp_socket ();
- X disable_special_privileges ();
- X if (fd < 0)
- X return EOF;
- X bcopy ((char *) hp->h_addr_list[i], (char *) &s.sin_addr,
- X sizeof (s.sin_addr));
- X if (debug)
- X fprintf (stderr, "Trying %s...", inet_ntoa (s.sin_addr));
- X last_connect_failed = 0; /* "I'm ashamed of this." - SMK */
- X if (connect (fd, &s, sizeof s) == 0) {
- X if (debug)
- X fprintf (stderr, "open\n");
- X break;
- X }
- X else {
- X close (fd); /* reuse fd */
- X if (debug)
- X perror ("");
- X last_connect_failed = 1;
- X }
- X }
- X if (last_connect_failed) {
- X perror ("connect");
- X return EOF;
- X }
- X#else
- X fd = get_priv_tcp_socket ();
- X disable_special_privileges ();
- X if (fd < 0)
- X return EOF;
- X bcopy ((char *) hp->h_addr, (char *) &s.sin_addr, sizeof(s.sin_addr));
- X if (connect (fd, &s, sizeof s) < 0) {
- X perror ("connect");
- X close (fd);
- X return EOF;
- X }
- X#endif
- X
- X max_net_read = max_net_write = 32767;
- X return fd;
- X}
- X
- X/*
- X * initialized data structures for disable_special_privileges (), below
- X */
- X
- int curr_proc_privs[2] = { 0, 0 }; /* current (image+perm) proc privs */
- int perm_proc_privs[2] = { 0, 0 }; /* permanent process privileges */
- int privs_length = 2;
- X
- struct item_list jpi_item_list[] = {
- X { sizeof curr_proc_privs, JPI$_CURPRIV, curr_proc_privs, &privs_length },
- X { sizeof perm_proc_privs, JPI$_PROCPRIV, perm_proc_privs, &privs_length },
- X { 0 },
- X};
- X
- X/*
- X * Turn off set-uid privileges.
- X * We have to have either SYSPRV or BYPASS privilege to bind to a privileged
- X * port. In order to minimize the security risk, we want to turn off these
- X * privileges as soon as we acquire the binding. This function turns off
- X * all privileges that are specific to this image.
- X */
- X
- static int
- disable_special_privileges ()
- X{
- X int status;
- X int privs_to_disable[2];
- X
- X /* get current privileges */
- X if ((status = sys$getjpiw (0, 0, 0, jpi_item_list, 0, 0, 0)) != SS$_NORMAL)
- X exit (status);
- X /*
- X * Turn off any privileges that aren't in the permanent process priv mask.
- X */
- X privs_to_disable[0] = curr_proc_privs[0] & ~perm_proc_privs[0];
- X privs_to_disable[1] = curr_proc_privs[1] & ~perm_proc_privs[1];
- X
- X if ((status = sys$setprv (0, privs_to_disable, 0, 0)) != SS$_NORMAL)
- X exit (status);
- X}
- X
- X/*
- X * bcopy() is not provided by the VMS C library
- X * This version is not particularly efficient, but we don't use it enough
- X * here to write a better version.
- X */
- X
- void
- bcopy (src, dest, length)
- register char *src, *dest;
- unsigned int length;
- X{
- X if (length == 0)
- X return;
- X do {
- X *dest++ = *src++;
- X } while (--length);
- X}
- X
- X/*
- X * unlink() is not provided by the VMS C library (for reasons which have
- X * always eluded me). delete() does essentially the same thing, but
- X * doesn't return the same error codes as unlink. It is, however, sufficient
- X * for our purposes.
- X */
- X
- int
- unlink (filename)
- char *filename;
- X{
- X return delete (filename);
- X}
- END_OF_FILE
- if test 8256 -ne `wc -c <'vms-ucx-tcp.c'`; then
- echo shar: \"'vms-ucx-tcp.c'\" unpacked with wrong size!
- fi
- # end of 'vms-ucx-tcp.c'
- fi
- if test -f 'vms-decnet.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'vms-decnet.c'\"
- else
- echo shar: Extracting \"'vms-decnet.c'\" \(3448 characters\)
- sed "s/^X//" >'vms-decnet.c' <<'END_OF_FILE'
- X/*
- X * lpr interface for VAX/VMS DECnet
- X */
- X
- X#include "common.h"
- X#include "config.h"
- X#include <stdio.h>
- X#include <ctype.h>
- X#include <lnmdef.h>
- X
- struct item_list {
- X unsigned short buffer_length;
- X unsigned short item_code;
- X char *buffer_address;
- X char *length_address;
- X};
- X
- struct descrip {
- X int length;
- X char *ptr;
- X};
- X
- X/*
- X * Translate a VAX/VMS logical name, given the name we want to translate
- X * and the table name we want to search with.
- X */
- X
- int
- translate_logical_name (table, name, buf, size)
- char *table; char *name; char *buf; int size;
- X{
- X struct descrip table_d;
- X struct descrip name_d;
- X struct item_list item_list[2];
- X int foo;
- X int status;
- X
- X table_d.length = strlen (table);
- X table_d.ptr = table;
- X name_d.length = strlen (name);
- X name_d.ptr = name;
- X item_list[0].buffer_length = size - 1;
- X item_list[0].item_code = LNM$_STRING;
- X item_list[0].buffer_address = buf;
- X item_list[0].length_address = &foo;
- X item_list[1].buffer_length = 0;
- X item_list[1].item_code = 0;
- X item_list[1].buffer_address = 0;
- X item_list[1].length_address = 0;
- X status = SYS$TRNLNM (0, &table_d, &name_d, 0, item_list);
- X if ((status & 01) != 01)
- X lib$signal (status);
- X if (foo >= 0 && foo < size)
- X buf[foo] = '\0';
- X return ((status & 01) ? 0 : EOF);
- X}
- X
- X/*
- X * Determine the DECnet node name by translating the system logical name
- X * SYS$NODE. We use this function rather than the getenv() function,
- X * just to make sure the user doesn't define his/her own SYS$NODE variable
- X * and pretend he/she is submitting the print job from somewhere else.
- X */
- X
- int
- get_decnet_node_name (buf, size)
- char *buf; int size;
- X{
- X char *strrchr ();
- X if (!translate_logical_name ("LNM$SYSTEM_TABLE", "SYS$NODE", buf, size)) {
- X char *p;
- X while (p = strrchr (buf, ':'))
- X *p = '\0';
- X return 0;
- X }
- X return EOF;
- X}
- X
- X#ifndef MAKE_EMAIL_ADDRESS
- X#define MAKE_EMAIL_ADDRESS(buf,user,dom) sprintf (buf, "%s@%s", user, dom)
- X#endif
- X
- void
- sysdep()
- X{
- X struct passwd *pwd;
- X char *p;
- X struct hostent *hp;
- X char *getenv ();
- X char nodename[100];
- X
- X get_decnet_node_name (nodename, sizeof(nodename));
- X strcpy (hostname, nodename);
- X
- X /* get user name (will be in ALL CAPS - yikes!) */
- X cuserid (username);
- X
- X MAKE_EMAIL_ADDRESS(email_address, username, hostname);
- X
- X /* lower case host name and user name */
- X for (p = hostname; *p; ++p)
- X if (isupper (*p))
- X *p = tolower (*p);
- X
- X for (p = username; *p; ++p)
- X if (isupper (*p))
- X *p = tolower (*p);
- X}
- X
- X/*
- X * Open a DECnet connection to an lpd-server.
- X */
- X
- int
- open_lpd (server)
- char *server;
- X{
- X int fd;
- X char buf[512];
- X
- X if (server == NULL || *server == '\0') {
- X fprintf (stderr, "lpr: no printer server host is defined\n");
- X fprintf (stderr, " Either specify one using -S, or\n");
- X fprintf (stderr, " using the logical name LPD_SERVER.\n");
- X return EOF;
- X }
- X sprintf (buf, "%s::\"223=\"", server);
- X if ((fd = open (buf, 2)) < 0) {
- X fprintf (stderr, "cannot open remote DECnet object '%s'\n", buf);
- X perror ("");
- X }
- X max_net_read = max_net_write = 512;
- X return fd;
- X}
- X
- X/*
- X * unlink() is not provided by the VMS C library (for reasons which have
- X * always eluded me). delete() does essentially the same thing, but
- X * doesn't return the same error codes as unlink. It is, however, sufficient
- X * for our purposes.
- X */
- X
- int
- unlink (filename)
- char *filename;
- X{
- X return delete (filename);
- X}
- X
- END_OF_FILE
- if test 3448 -ne `wc -c <'vms-decnet.c'`; then
- echo shar: \"'vms-decnet.c'\" unpacked with wrong size!
- fi
- # end of 'vms-decnet.c'
- fi
- if test -f 'vms-win-tcp.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'vms-win-tcp.c'\"
- else
- echo shar: Extracting \"'vms-win-tcp.c'\" \(9046 characters\)
- sed "s/^X//" >'vms-win-tcp.c' <<'END_OF_FILE'
- X/*
- X * lpr interface for Wollengong's WIN/TCP for VAX/VMS
- X */
- X
- X#include "common.h"
- X#include "config.h"
- X#include <stdio.h>
- X#include <ctype.h>
- X/*
- X * Our (old) version of WIN/TCP has definitions in its include files that
- X * conflict with the definitions in the VMS system library include files.
- X * So I have pulled out only those definitions I need for this module.
- X */
- X/* #include "twg$tcp:[netdist.include.sys]types.h" */
- typedef unsigned short u_short;
- typedef unsigned long u_long;
- typedef char * caddr_t;
- X/* #include "twg$tcp:[netdist.include.sys]stat.h" */
- X#include "twg$tcp:[netdist.include]netdb.h"
- X#include "twg$tcp:[netdist.include.sys]socket.h"
- X/*
- X * WIN/TCP's errno.h puts errno in a different program segment than
- X * the one in sys$library. The only define we use here is EACCES
- X * which is the same in both places. If you are running an old
- X * version of VMS, you might have to change this a bit.
- X */
- X/* #include "twg$tcp:[netdist.include]errno.h" */
- X#include <errno.h>
- X#include "twg$tcp:[netdist.include.netinet]in.h"
- X#include <prvdef.h>
- X#include <jpidef.h>
- X#include <ssdef.h>
- X#include <lnmdef.h>
- X
- struct item_list {
- X unsigned short buffer_length;
- X unsigned short item_code;
- X char *buffer_address;
- X char *length_address;
- X};
- X
- struct descrip {
- X int length;
- X char *ptr;
- X};
- X
- X/*
- X * Translate a VAX/VMS logical name, given the name we want to translate
- X * and the table name we want to search with.
- X */
- X
- int
- translate_logical_name (table, name, buf, size)
- char *table; char *name; char *buf; int size;
- X{
- X struct descrip table_d;
- X struct descrip name_d;
- X struct item_list item_list[2];
- X int foo;
- X int status;
- X
- X table_d.length = strlen (table);
- X table_d.ptr = table;
- X name_d.length = strlen (name);
- X name_d.ptr = name;
- X item_list[0].buffer_length = size - 1;
- X item_list[0].item_code = LNM$_STRING;
- X item_list[0].buffer_address = buf;
- X item_list[0].length_address = &foo;
- X item_list[1].buffer_length = 0;
- X item_list[1].item_code = 0;
- X item_list[1].buffer_address = 0;
- X item_list[1].length_address = 0;
- X status = SYS$TRNLNM (0, &table_d, &name_d, 0, item_list);
- X if ((status & 01) != 01)
- X lib$signal (status);
- X if (foo >= 0 && foo < size)
- X buf[foo] = '\0';
- X return ((status & 01) ? 0 : EOF);
- X}
- X
- X/*
- X * Determine the DECnet node name by translating the system logical name
- X * SYS$NODE. We use this function rather than the getenv() function,
- X * just to make sure the user doesn't define his/her own SYS$NODE variable
- X * and pretend he/she is submitting the print job from somewhere else.
- X */
- X
- int
- get_decnet_node_name (buf, size)
- char *buf; int size;
- X{
- X
- X if (!translate_logical_name ("LNM$SYSTEM_TABLE", "SYS$NODE", buf, size)) {
- X char *p;
- X while ((p = strrchr (buf, ':')))
- X *p = '\0';
- X return 0;
- X }
- X return EOF;
- X}
- X
- X#ifndef MAKE_EMAIL_ADDRESS
- X#define MAKE_EMAIL_ADDRESS(buf,user,dom) sprintf (buf, "%s@%s", user, dom)
- X#endif
- X
- struct hostent *
- gethostbynameoraddr (hostname)
- char *hostname;
- X{
- X if (isdigit (*hostname)) {
- X static struct hostent x;
- X static char *alias_list[1];
- X static unsigned long *addr_list[2];
- X static unsigned long ip_address;
- X
- X ip_address = inet_addr (hostname);
- X
- X addr_list[0] = &ip_address;
- X addr_list[1] = NULL;
- X alias_list[0] = NULL;
- X
- X x.h_name = hostname;
- X x.h_aliases = alias_list;
- X x.h_addrtype = AF_INET;
- X x.h_length = sizeof (unsigned long);
- X x.h_addr_list = (char **) addr_list;
- X return &x;
- X }
- X return gethostbyname (hostname);
- X}
- X
- X
- void sysdep()
- X{
- X struct passwd *pwd;
- X char *p;
- X struct hostent *hp;
- X char *getenv ();
- X char nodename[100];
- X
- X get_decnet_node_name (nodename, sizeof(nodename));
- X gethostname (hostname, sizeof hostname);
- X
- X /* get user name (will be in ALL CAPS - yikes!) */
- X cuserid (username);
- X
- X hp = gethostbyname (hostname);
- X MAKE_EMAIL_ADDRESS(email_address, username, hp ? hp->h_name : hostname);
- X
- X /* lower case host name and user name */
- X for (p = hostname; *p; ++p)
- X if (isupper (*p))
- X *p = tolower (*p);
- X
- X for (p = username; *p; ++p)
- X if (isupper (*p))
- X *p = tolower (*p);
- X}
- X
- X
- X/*
- X * Allocate a socket and bind it to a local privileged port
- X * We have to be running set-uid to root to do this.
- X */
- X
- int
- get_priv_tcp_socket ()
- X{
- X int fd;
- X int port;
- X struct sockaddr_in s;
- X
- X if ((fd = socket (AF_INET, SOCK_STREAM, 0)) == EOF) {
- X perror ("socket");
- X return EOF;
- X }
- X for (port = IPPORT_RESERVED-1; port > IPPORT_RESERVED / 2; port--) {
- X extern int errno;
- X s.sin_family = AF_INET;
- X s.sin_addr.s_addr = INADDR_ANY;
- X s.sin_port = htons (port);
- X if (bind (fd, (struct sockaddr *) &s, sizeof (s)) == 0)
- X return fd;
- X if (errno == EACCES) {
- X fprintf (stderr, "lpr warning: bind: cannot bind to privileged port\n");
- X return fd;
- X }
- X }
- X close (fd);
- X return EOF;
- X}
- X
- X/*
- X * Open a TCP connection to an lpd-server.
- X * This requires that this program be run set-uid to root in order to be able
- X * to bind a socket to a privileged port.
- X */
- X
- int
- open_lpd (server)
- char *server;
- X{
- X int fd;
- X int i;
- X int last_connect_failed;
- X struct hostent *hp;
- X struct servent *sp;
- X struct sockaddr_in s;
- X void bcopy ();
- X
- X if (server == NULL || *server == '\0') {
- X fprintf (stderr, "lpr: no server host was specified.\n");
- X fprintf (stderr, " Supply one with the -S option, or\n");
- X fprintf (stderr, " by defining the LPD_SERVER logical name\n");
- X return EOF;
- X }
- X if ((hp = gethostbynameoraddr (server)) == NULL) {
- X fprintf (stderr, "lpr: can't find network address for %s\n",
- X server);
- X fflush (stderr);
- X return EOF;
- X }
- X
- X s.sin_family = AF_INET;
- X#if 1
- X /* some bug in the VMS C optimizer seems to require this */
- X s.sin_port = htons (515);
- X#else
- X if ((sp = getservbyname ("printer", "tcp")) == NULL)
- X s.sin_port = htons (515);
- X else
- X s.sin_port = sp->s_port;
- X#endif
- X
- X /*
- X * On some systems h_addr is a macro that is defined to be h_addr_list[0]
- X * On other (ancient) systems, h_addr is a member of the hostent structure.
- X * So if h_addr is defined as a macro, then we must have the list...
- X */
- X
- X#ifdef h_addr
- X for (i = 0; hp->h_addr_list[i] ; ++i) {
- X fd = get_priv_tcp_socket ();
- X disable_special_privileges ();
- X if (fd < 0)
- X return EOF;
- X bcopy ((char *) hp->h_addr_list[i], (char *) &s.sin_addr,
- X sizeof (s.sin_addr));
- X if (debug)
- X fprintf (stderr, "Trying %s...", inet_ntoa (s.sin_addr));
- X last_connect_failed = 0; /* "I'm ashamed of this." - SMK */
- X if (connect (fd, &s, sizeof s) == 0) {
- X if (debug)
- X fprintf (stderr, "open\n");
- X break;
- X }
- X else {
- X close (fd); /* reuse fd */
- X if (debug)
- X perror ("");
- X last_connect_failed = 1;
- X }
- X }
- X if (last_connect_failed) {
- X perror ("connect");
- X return EOF;
- X }
- X#else
- X fd = get_priv_tcp_socket ();
- X disable_special_privileges ();
- X if (fd < 0)
- X return EOF;
- X bcopy ((char *) hp->h_addr, (char *) &s.sin_addr, sizeof(s.sin_addr));
- X if (connect (fd, &s, sizeof s) < 0) {
- X perror ("connect");
- X close (fd);
- X return EOF;
- X }
- X#endif
- X
- X max_net_read = max_net_write = 32767;
- X return fd;
- X}
- X
- X/*
- X * initialized data structures for disable_special_privileges (), below
- X */
- X
- int curr_proc_privs[2] = { 0, 0 }; /* current (image+perm) proc privs */
- int perm_proc_privs[2] = { 0, 0 }; /* permanent process privileges */
- int privs_length = 2;
- X
- struct item_list jpi_item_list[] = {
- X { sizeof curr_proc_privs, JPI$_CURPRIV, curr_proc_privs, &privs_length },
- X { sizeof perm_proc_privs, JPI$_PROCPRIV, perm_proc_privs, &privs_length },
- X { 0 },
- X};
- X
- X/*
- X * Turn off set-uid privileges.
- X * We have to have either SYSPRV or BYPASS privilege to bind to a privileged
- X * port. In order to minimize the security risk, we want to turn off these
- X * privileges as soon as we acquire the binding. This function turns off
- X * all privileges that are specific to this image.
- X */
- X
- int
- disable_special_privileges ()
- X{
- X int status;
- X int privs_to_disable[2];
- X
- X /* get current privileges */
- X if ((status = sys$getjpiw (0, 0, 0, jpi_item_list, 0, 0, 0)) != SS$_NORMAL)
- X exit (status);
- X /*
- X * Turn off any privileges that aren't in the permanent process priv mask.
- X */
- X privs_to_disable[0] = curr_proc_privs[0] & ~perm_proc_privs[0];
- X privs_to_disable[1] = curr_proc_privs[1] & ~perm_proc_privs[1];
- X
- X if ((status = sys$setprv (0, privs_to_disable, 0, 0)) != SS$_NORMAL)
- X exit (status);
- X}
- X
- X/*
- X * bcopy() is not provided by the VMS C library
- X * This version is not particularly efficient, but we don't use it enough
- X * here to write a better version.
- X */
- X
- void
- bcopy (src, dest, length)
- register char *src, *dest;
- unsigned int length;
- X{
- X if (length == 0)
- X return;
- X do {
- X *dest++ = *src++;
- X } while (--length);
- X}
- X
- X/*
- X * unlink() is not provided by the VMS C library (for reasons which have
- X * always eluded me). delete() does essentially the same thing, but
- X * doesn't return the same error codes as unlink. It is, however, sufficient
- X * for our purposes.
- X */
- X
- int
- unlink (filename)
- char *filename;
- X{
- X return delete (filename);
- X}
- END_OF_FILE
- if test 9046 -ne `wc -c <'vms-win-tcp.c'`; then
- echo shar: \"'vms-win-tcp.c'\" unpacked with wrong size!
- fi
- # end of 'vms-win-tcp.c'
- fi
- if test -f 'descrip.mms' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'descrip.mms'\"
- else
- echo shar: Extracting \"'descrip.mms'\" \(739 characters\)
- sed "s/^X//" >'descrip.mms' <<'END_OF_FILE'
- X# Makefile for VMS MMS (Module Management System)
- X# You may have to modify this file slightly to work on other VMS make clones
- X#
- X# pick a back-end driver from one of the following:
- X#
- X#DRIVER=vms-ucx-tcp.obj # VMS Ultrix Connection
- X#DRIVER=vms-win-tcp.obj # VMS WIN/TCP
- DRIVER=vms-decnet.obj # DECnet-VAX (requires gateway on UNIX)
- X#
- X# pick a library to go with the driver
- X#
- X#LIBRARY=sys$library:ucx$ipc.olb/lib # VMS Ultrix Connection
- X#LIBRARY=twg$tcp:[netdist.lib]twglib.olb/lib # VMS WIN/TCP
- LIBRARY=sys$library:vaxcrtl.olb/lib # dummy for DECnet
- X#
- X#
- CFLAGS=/debug
- LDFLAGS=
- X#
- lpr.exe : lpr.obj $(DRIVER)
- X LINK $(LDFLAGS) lpr.obj,$(DRIVER),$(LIBRARY)
- X
- lpr.obj : lpr.c config.h
- X $(CC) $(CFLAGS) lpr.c
- X
- X
- clean :
- X del lpr.exe;*,*.obj;*
- END_OF_FILE
- if test 739 -ne `wc -c <'descrip.mms'`; then
- echo shar: \"'descrip.mms'\" unpacked with wrong size!
- fi
- # end of 'descrip.mms'
- fi
- if test -f 'dnet-lpd-gw.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'dnet-lpd-gw.c'\"
- else
- echo shar: Extracting \"'dnet-lpd-gw.c'\" \(5508 characters\)
- sed "s/^X//" >'dnet-lpd-gw.c' <<'END_OF_FILE'
- X/*
- X * line printer daemon gateway for DECnet
- X *
- X * Listens on a DECnet port and copies packets to/from the local
- X * Berkeley line printer daemon.
- X */
- X
- X#include <stdio.h>
- X#include <sys/types.h>
- X#include <sys/socket.h>
- X#include <netinet/in.h>
- X#include <sys/un.h>
- X#include <netdb.h>
- X#include <ctype.h>
- X#include <errno.h>
- X#define MAIN_PROGRAM
- X#include "common.h"
- X
- X
- char *DECnet_remoteNode;
- char *DECnet_remoteUser;
- X
- void
- dump_buf (fp, prefix, buf, size)
- unsigned char *prefix, *buf;
- int size;
- XFILE *fp;
- X{
- X int i;
- X fprintf (fp, "%s ", prefix);
- X for (i = 0; i < size; ++i)
- X if (buf[i] >= ' ' && buf[i] <= '~')
- X putc (buf[i], fp);
- X else if (buf[i] == '\n')
- X fprintf (fp, "\\n");
- X else
- X fprintf (fp, "\\%03o", buf[i] & 0377);
- X putc ('\n', fp);
- X fflush (fp);
- X}
- X
- char *
- strsave (s)
- char *s;
- X{
- X char *malloc ();
- X char *p;
- X if (s == NULL)
- X return NULL;
- X if ((p = malloc (strlen (s) + 1)) == NULL)
- X return NULL;
- X strcpy (p, s);
- X return p;
- X}
- X
- X
- X#ifdef sun
- X/*
- X * accept code for SunLink DNI
- X */
- X
- X#include <sys/ioctl.h>
- X#include <netdni/dni.h>
- X
- int
- accept_decnet_connection ()
- X{
- X OpenBlock open_block;
- X SessionData session_data;
- X int dnet_fd;
- X
- X dnet_fd = 3;
- X if (ioctl (dnet_fd, SES_GET_AI, &open_block) < 0) {
- X fprintf (stderr, "dnet-lpd: can't get access control information\n");
- X fflush (stderr);
- X return EOF;
- X }
- X DECnet_remoteNode = strsave (open_block.op_node_name);
- X DECnet_remoteUser = strsave (open_block.op_userid);
- X if (ioctl (dnet_fd, SES_ACCEPT, &session_data) < 0) {
- X fprintf (stderr, "dnet-lpd: can't accept inbound connection\n");
- X fflush (stderr);
- X return EOF;
- X }
- X return dnet_fd;
- X}
- X#endif
- X
- X
- X#ifdef ultrix
- X/*
- X * accept code for DECnet-Ultrix (untested)
- X */
- X
- X#include <netdnet/dn.h>
- X
- int
- accept_decnet_connection ()
- X{
- X struct accessdata_dn acc_data;
- X int dnet_fd = 0;
- X
- X setsockopt (dnet_fd, DNPROTO_NSP, DSO_CONACCESS, &acc_data,
- X sizeof (acc_data));
- X DECnet_remoteNode = strsave (getenv ("REMNODE"));
- X DECnet_remoteUser = strsave (getenv ("REMUSER"));
- X setsockopt (dnet_fd, DNPROTO_NSP, DSO_CONACCEPT, 0, 0);
- X return dnet_fd;
- X}
- X#endif
- X
- int
- x_read (fd, buf, size)
- int fd; char *buf; unsigned size;
- X{
- X int nread = read (fd, (char *) buf, size);
- X char prefix[10];
- X sprintf (prefix, "<%d<", fd);
- X if (debug)
- X dump_buf (stderr, prefix, buf, nread);
- X return nread;
- X}
- X
- int
- x_write (fd, buf, size)
- int fd; char *buf; unsigned size;
- X{
- X char prefix[10];
- X sprintf (prefix, ">%d>", fd);
- X if (debug)
- X dump_buf (stderr, prefix, buf, size);
- X return write (fd, (char *) buf, size);
- X}
- X
- int
- y_read (fd, buf, size)
- int fd; char *buf; unsigned size;
- X{
- X int nread = read (fd, (char *) buf, size);
- X if (debug)
- X fprintf (stderr, "<%d< (%d bytes)\n", fd, nread);
- X return nread;
- X}
- X
- int
- y_write (fd, buf, size)
- int fd; char *buf; unsigned size;
- X{
- X if (debug)
- X fprintf (stderr, ">%d> (%d bytes)\n", fd, size);
- X return write (fd, (char *) buf, size);
- X}
- X
- do_gateway (dnet_fd, tcp_fd)
- int dnet_fd, tcp_fd;
- X{
- X char buf[512];
- X int nread;
- X
- X while ((nread = x_read (dnet_fd, buf, sizeof buf)) > 0) {
- X switch (*buf) {
- X case '\02': /* receive a printer job */
- X x_write (tcp_fd, buf, nread);
- X nread = x_read (tcp_fd, buf, sizeof buf);
- X if (nread > 0) {
- X x_write (dnet_fd, buf, nread);
- X receive_job (dnet_fd, tcp_fd);
- X }
- X else
- X exit (0);
- X break;
- X case '\01': /* print any waiting jobs */
- X case '\03': /* display queue state (short) */
- X case '\04': /* display queue state (long) */
- X case '\05': /* remove jobs */
- X default:
- X x_write (tcp_fd, buf, nread);
- X while ((nread = x_read (tcp_fd, buf, sizeof buf)) > 0)
- X x_write (dnet_fd, buf, nread);
- X exit (0);
- X }
- X }
- X}
- X
- receive_job (dnet_fd, tcp_fd)
- int dnet_fd, tcp_fd;
- X{
- X char buf[512];
- X int nread;
- X int count;
- X
- X while ((nread = x_read (dnet_fd, buf, sizeof buf)) > 0) {
- X switch (*buf) {
- X case '\01':
- X default:
- X x_write (tcp_fd, buf, nread);
- X nread = x_read (tcp_fd, buf, sizeof buf);
- X if (nread > 0)
- X x_write (dnet_fd, buf, nread);
- X else
- X exit (0);
- X case '\02': /* send control file */
- X case '\03': /* send data file */
- X count = atoi (buf + 1); /* length of control file */
- X /* copy command to lpd ; get response*/
- X x_write (tcp_fd, buf, nread);
- X nread = x_read (tcp_fd, buf, sizeof buf);
- X if (nread > 0)
- X x_write (dnet_fd, buf, nread);
- X else
- X exit (0);
- X copy_file (dnet_fd, tcp_fd, count);
- X }
- X }
- X}
- X
- copy_file (src, dest, size)
- int src, dest, size;
- X{
- X int nread;
- X char buf[512];
- X
- X while (size > 0) {
- X if ((nread = y_read (src, buf, sizeof buf)) > 0) {
- X y_write (dest, buf, nread);
- X size -= nread;
- X }
- X else
- X break;
- X }
- X if (size > 0) {
- X int x;
- X
- X bzero (buf, sizeof buf);
- X while (size > 0) {
- X x = size > 512 ? 512 : size;
- X y_write (dest, buf, x);
- X size -= x;
- X }
- X }
- X nread = x_read (src, buf, sizeof buf); /* should be a NUL octet */
- X x_write (dest, buf, nread);
- X nread = x_read (dest, buf, sizeof buf); /* acknowlegement */
- X x_write (src, buf, nread);
- X}
- X
- int debug = 0;
- X
- main (argc, argv)
- char **argv;
- X{
- X int dnet_fd, tcp_fd;
- X if (debug)
- X freopen ("/tmp/dnet-lpd-gw.log", "a", stderr);
- X
- X if ((dnet_fd = accept_decnet_connection ()) < 0) {
- X fprintf (stderr, "DECnet accept failed, exiting\n");
- X exit (1);
- X }
- X if ((tcp_fd = open_lpd ("localhost")) < 0) {
- X fprintf (stderr, "TCP open failed, exiting\n");
- X exit (1);
- X }
- X do_gateway (dnet_fd, tcp_fd);
- X exit (0);
- X}
- X
- END_OF_FILE
- if test 5508 -ne `wc -c <'dnet-lpd-gw.c'`; then
- echo shar: \"'dnet-lpd-gw.c'\" unpacked with wrong size!
- fi
- # end of 'dnet-lpd-gw.c'
- fi
- if test -f 'lpr.man' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'lpr.man'\"
- else
- echo shar: Extracting \"'lpr.man'\" \(9647 characters\)
- sed "s/^X//" >'lpr.man' <<'END_OF_FILE'
- X.TH LPR 1 "21 March 1991"
- X.SH NAME
- lpr \- ``standalone'' interface to a remote BSD printer spooler
- X.SH SYNOPSIS
- X.B lpr
- X[
- X.BI \- job-option
- X\&... ] [
- X.BI \- file-option
- X\&... ] [
- X.I filename
- X\&... ]
- X.br
- X.B lprm
- X[
- X.BI \-P printer
- X] [
- X.B \-
- X]
- X.I args...
- X.br
- X.B lpq
- X[
- X.BI \-P printer
- X] [
- X.B \-l
- X]
- X.I args
- X.SH DESCRIPTION
- This version of
- X.B lpr
- is an interface to a remote BSD UNIX-style printer spooler that allows
- a user of a non-BSD UNIX system to print files on printers attached to
- a server that supports the BSD print spooler protocol.
- X.PP
- When
- X.IR filename s
- are supplied on the command line,
- X.B lpr
- prints the named files. If no
- X.IR filename s
- appear, standard input is printed according to the supplied options.
- X.PP
- X.B lprm
- removes the jobs specified in \fIargs\fR from the remote print queue.
- The jobs must have been queued from the local host. \fIargs\fR
- consist of some combination of user names or job numbers. If no
- X\fIargs\fR are supplied, the currently active job is deleted. The
- argument ``\fB\-\fR'' is interpreted to mean ``delete all print jobs
- queued by this user,'' or if invoked by root, ``delete all print jobs
- queued from this host.''
- X.PP
- X.B lpq
- prints a listing of the jobs queued for that particular printer. The
- X\fB\-l\fR option prints a more verbose listing.
- X.SH ENVIRONMENT
- X.B lpr
- requires that the
- X.B LPD_SERVER
- environment variable contain the name of a printer server to which
- files are spooled. If this variable does not exist, an error message
- is printed.
- X.SH OPTIONS
- Options fall into two general categories: job options and file
- options. The former class of options affects an entire print job.
- The latter class affects only specific files and can be overriden for
- subsequent files. For example, it is possible to print a troff file
- and a plain text file in the same print job.
- X.PP
- Options that require arguments can be specified with or without
- intervening space between the option and the argument. Thus, either
- X.BI \-P printer
- or
- X.B \-P
- X.I printer
- will work.
- X.SS Job options
- X.PP
- These options specify parameters that affect the entire print job.
- These include:
- X.TP 15
- X.BI \-C jobclass
- Names the job class, which will appear on the job banner page. By default
- this is set to the local hostname.
- X.TP
- X.BI \-J jobtitle
- Names the job title, which will appear on the job banner page when printed.
- By default this is the name of the first file named on the command line.
- X.TP
- X.B \-h
- Tells the printer server to not print the banner page.
- X.TP
- X.B \-m
- When the print job completes, have the printer server send a mail message
- to the person who submitted the job. This requires that your machine be able
- to receive mail addressed to
- X.IR your-user-name @ your-host-name
- and that the print server be able to get it there.
- X.TP
- X.BI \-P printer
- specifies to which printer (of those attached to the printer server)
- output will be sent.
- X.TP
- X.BI \-q printer
- The
- X.B \-q
- option is synonymous with the
- X.B \-P
- option. This option is intended for use with VMS systems that cannot
- distinguish
- X.B \-P
- from
- X.B \-p. Since
- X.B \-p
- has another meaning,
- X.B \-q
- is used on
- VMS to select the printer. VMS users can also type
- X.BI \-P printer
- within double quotes.
- X.TP
- X.B \-r
- specifies that the named files are to be removed after being successfully
- transmitted to the remote printer spooler.
- X.TP
- X.B \-debug
- Show messages sent to and from the server on the standard error output.
- Not for the faint-of-heart.
- X.SS File options
- These options specify parameters that are particular to one or more of
- the files to be printed. These options pertain to any files that appear
- to the right of the option on the command line, but they may be
- overriden by specifing a different option between files.
- X.PP
- Only one of the file-type options
- X.RB ( \-d ,
- X.BR \-f ,
- X.BR \-g ,
- X.BR \-l ,
- X.BR \-n ,
- X.BR \-o ,
- X.BR \-p ,
- X.BR \-t ,
- and
- X.BR \-v )
- apply to any given file. Subsequent use of any of these options
- specifies the type of each file that appears to the right of the
- option, until another file-type option appears.
- X.PP
- In the absence of any file-type options,
- X.B lpr
- X.ds tE \s-1T\s-1\dE\u\s+1X\s+1
- tries to figure out what kind of file is to be printed. It can currently
- recognize \*(tE DVI files, as well as C/A/T (``classic'')
- X.BR troff (1)
- and PostScript files. If the particular
- kind of file is not recognized,
- X.B lpr
- assumes the file is an ordinary text file.
- X.TP 15
- X.BI \-# number
- Specifies the number of copies of each file to print. Default is to
- print one copy of each file.
- X.TP
- X.B \-d
- XFiles that follow this option are device-independent (DVI)
- files such as might be produced by \*(tE.
- X.TP
- X.B \-f
- Tells
- X.B lpr
- to expect files in FORTRAN output format, where the first
- character of each line determines how to handle the ``printer
- carraige'' after each line
- X.RB ( SPACE =go
- to next line,
- X.RB `` + ''=overprint,
- etc.)
- X.TP
- X.B \-g
- XFiles that follow this option are expected to be in V7 UNIX
- X.BR plot (5)
- format. (Very few spoolers support this format.)
- X.TP
- X.B \-l
- XFiles that follow this option are ordinary text files, but which may
- contain embedded control characters. (Some printer spoolers reject
- files which contain too many control characters; this option overrides
- that feature in order to allow users to make use of printer specific
- features that require use of non-printable characters.)
- X.TP
- X.B \-n
- Tells
- X.B lpr
- to expect files in device-independent troff
- X.RB ( ditroff )
- format. (Many spoolers do not support this format.)
- X.TP
- X.B \-o
- Tells
- X.B lpr
- to expect PostScript\v'-.5'\(tm\v'.5' files. This generally
- requires that the printer itself speak PostScript. Furthermore, many
- printer spoolers do not grok
- X.BR \-o ,
- but do accept PostScript files submitted as ``normal text'' files,
- interpreting them as PostScript programs rather than ordinary text files.
- X.TP
- X.B \-p
- Tells
- X.B lpr
- that subsequent files are ordinary text files, which should
- be printed with page breaks and headers.
- X.TP
- X.B \-t
- Tells
- X.B lpr
- to expect files generated for a C/A/T phototypesetter, such
- as are generated by old or ``classic''
- X.BR troff .
- X.TP
- X.B \-v
- Tells
- X.B lpr
- to expect Versatec raster-format files, or files in the
- printer's native format, whatever that is.
- X.SH DIAGNOSTICS
- X.TP 5
- X.B "LPD_SERVER environment variable is not set"
- The environment variable
- X.B LPD_SERVER
- must be set to the name of the printer server.
- X.TP
- X.B "bind: cannot bind to privileged port"
- XEither no privileged ports are available (highly unlikely), or
- X.B lpr
- is not installed as a privileged program. Tell your system manager to
- read the installation instructions again.
- X.TP
- X.B "can't find network address for \fIserver\fB"
- An attempt to determine the network address of the printer server
- failed. The server must be listed in the Internet name server, your
- system's
- X.B /etc/hosts
- file, or in the NIS hosts database, depending on which mechanism your
- system uses for translating host names to network addresses.
- X.TP
- X.B "\fIfilename\fB is a TeX .dvi file, assuming \-d"
- The named file begins and ends with the magic numbers used by \*(tE
- DVI files, and will therefore be interpreted as such instead of spewing
- garbage to the printer.
- X.TP
- X.B "\fIfilename\fB is a C/A/T troff output file, assuming \-t"
- The file begins with the magic number generated by C/A/T (``classic'')
- X.BR troff (1),
- and will therefore be interpreted as such.
- X.TP
- X.B "\fIfilename\fB is a UNIX library archive \-\- ignoring it"
- X.B lpr
- refuses to print library archive files, since these usually contain
- non-printable data.
- X.TP
- X.B "\fIfilename\fB is a compressed file \-\- ignoring it"
- The named file has been compressed with
- X.BR compress (1),
- and cannot be directly printed by
- X.BR lpr .
- XEither use
- X.BR uncompress (1)
- to restore the original file, or pipe the file through
- X.BR zcat (1).
- X.TP
- X.B "skipping zero length file \fIfilename\fR"
- X.B lpr
- optimizes the printing of an empty file by skipping the file entirely,
- thus saving trees by not printing unwanted banner pages.
- X.TP
- X.B "\fIfilename\fB is not a valid .dvi file"
- The
- X.B \-d
- option was specified, but the named file is not in DVI format.
- X.SH BUGS
- X.LP
- There is currently no way to delete a print job (analogous to the BSD
- X.B lprm
- command), nor to inquire on the status of the print queue (analogus to the BSD
- X.B lpq
- command).
- X.LP
- The protocol used by
- X.B lpr
- requires that it know the exact size of a file before sending it to
- the print spooler. In order to compute the size of a file piped to
- standard input, and in order to work on non-UNIX systems which cannot
- determine the exact size of a file,
- X.B lpr
- reads each file into memory (counting the bytes as it goes) before
- sending it to the spooler. Therefore, files larger than available
- memory cannot be printed.
- X.LP
- Not all printers or spoolers support all file types. There is no
- agreement among the various spoolers as to how to treat the
- X.B \-v
- file type.
- X.LP
- The
- X.BR \-T ,
- X.BR \-i ,
- X.BR \-s ,
- and
- X.B \-w
- options of BSD
- X.B lpr
- are not supported.
- X.LP
- Job numbers are just independently-generated random numbers between 0
- and 999, so conflicts between two jobs submitted on the same host are
- possible.
- X.LP
- The VMS interface is crufty. LPR on VMS should take VMS-style options,
- and return a reasonable error status, but it doesn't do that yet.
- X.SH SEE ALSO
- X.LP
- X.I Line printer daemon protocol, RFC1179.
- X.LP
- Documentation for the printer spooler you are using on the printer server.
- On BSD UNIX and some other systems, see the man pages for
- X.BR lpq (1),
- X.BR lprm (1),
- X.BR lpc (8),
- and
- X.BR lpd (8).
- X.\"* (emacs file trailier)
- X.\" Local Variables:
- X.\" auto-fill-mode:t
- X.\" version-control:t
- X.\" paragraph-separate:"^\\."
- X.\" paragraph-start:"^\\."
- X.\" End:
- END_OF_FILE
- if test 9647 -ne `wc -c <'lpr.man'`; then
- echo shar: \"'lpr.man'\" unpacked with wrong size!
- fi
- # end of 'lpr.man'
- fi
- if test -f 'lpr.cat' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'lpr.cat'\"
- else
- echo shar: Extracting \"'lpr.cat'\" \(14024 characters\)
- uudecode <<'END_OF_FILE'
- begin 644 lpr.cat
- M"@H*3%!2*#$I("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@
- M("`@("`@("`@("`@("`@("!,4%(H,2D*"@I."$Y!"$%-"$U%"$4*("`@("`@
- M(&QP<B`@+2`@8&!S=&%N9&%L;VYE)R<@(&EN=&5R9F%C92`@=&\@82!R96UO
- M=&4@0E-$('!R:6YT97(*("`@("`@('-P;V]L97(*"E,(4UD(64X(3D\(3U`(
- M4%,(4TD(25,(4PH@("`@("`@;`AL<`AP<@AR(%L@+0@M7PAJ7PAO7PAB7P@M
- M7PAO7PAP7PAT7PAI7PAO7PAN("XN+B!=(%L@+0@M7PAF7PAI7PAL7PAE7P@M
- M7PAO7PAP7PAT7PAI7PAO7PAN("XN+B`@72`@6R`@7PAF7PAI7PAL7PAE7PAN
- M7PAA7PAM7PAE"B`@("`@("`N+BX@70H@("`@("`@;`AL<`AP<@AR;0AM(%L@
- M+0@M4`A07PAP7PAR7PAI7PAN7PAT7PAE7PAR(%T@6R`M""T@72!?"&%?"')?
- M"&=?"'-?""Y?""Y?""X*("`@("`@(&P(;'`(<'$(<2!;("T(+5`(4%\(<%\(
- M<E\(:5\(;E\(=%\(95\(<B!=(%L@+0@M;`AL(%T@7PAA7PAR7PAG7PAS"@I$
- M"$1%"$53"%-#"$-2"%))"$E0"%!4"%1)"$E/"$]."$X*("`@("`@(%1H:7,@
- M('9E<G-I;VX@;V8@;`AL<`AP<@AR(&ES(&%N(&EN=&5R9F%C92!T;R!A(')E
- M;6]T92!"4T0@54Y)6"T*("`@("`@('-T>6QE('!R:6YT97(@<W!O;VQE<B!T
- M:&%T(&%L;&]W<R!A('5S97(@;V8@82!N;VXM0E-$(%5.25@*("`@("`@('-Y
- M<W1E;2`@=&\@('!R:6YT("!F:6QE<R`@;VX@<')I;G1E<G,@871T86-H960@
- M=&\@82!S97)V97(*("`@("`@('1H870@<W5P<&]R=',@=&AE($)31"!P<FEN
- M="!S<&]O;&5R('!R;W1O8V]L+@H*("`@("`@(%=H96X@7PAF7PAI7PAL7PAE
- M7PAN7PAA7PAM7PAE<R!A<F4@('-U<'!L:65D("!O;B`@=&AE("!C;VUM86YD
- M("!L:6YE+"`@;`AL<`AP<@AR"B`@("`@("!P<FEN=',@('1H92!N86UE9"!F
- M:6QE<RX@($EF(&YO(%\(9E\(:5\(;%\(95\(;E\(85\(;5\(97,@87!P96%R
- M+"!S=&%N9&%R9`H@("`@("`@:6YP=70@:7,@<')I;G1E9"!A8V-O<F1I;F<@
- M=&\@=&AE('-U<'!L:65D(&]P=&EO;G,N"@H@("`@("`@;`AL<`AP<@AR;0AM
- M(')E;6]V97,@=&AE(&IO8G,@<W!E8VEF:65D(&EN(%\(85\(<E\(9U\(<R`@
- M9G)O;2`@=&AE("!R96UO=&4*("`@("`@('!R:6YT("!Q=65U92X@("!4:&4@
- M(&IO8G,@(&UU<W0@(&AA=F4@8F5E;B!Q=65U960@9G)O;2!T:&4*("`@("`@
- M(&QO8V%L(&AO<W0N("!?"&%?"')?"&=?"',@8V]N<VES="`@;V8@('-O;64@
- M(&-O;6)I;F%T:6]N("!O9B`@=7-E<@H@("`@("`@;F%M97,@(&]R("!J;V(@
- M;G5M8F5R<RX@($EF(&YO(%\(85\(<E\(9U\(<R!A<F4@<W5P<&QI960L('1H
- M92!C=7(M"B`@("`@("!R96YT;'D@86-T:79E(&IO8B`@:7,@(&1E;&5T960N
- M("`@5&AE("!A<F=U;65N="`@8&`M""TG)R`@:7,*("`@("`@(&EN=&5R<')E
- M=&5D('1O(&UE86X@8&!D96QE=&4@86QL('!R:6YT(&IO8G,@<75E=65D(&)Y
- M('1H:7,*("`@("`@('5S97(L)R<@;W(@:68@:6YV;VME9"!B>2!R;V]T+"`@
- M8&!D96QE=&4@(&%L;"`@<')I;G0@(&IO8G,*("`@("`@('%U975E9"!F<F]M
- M('1H:7,@:&]S="XG)PH*("`@("`@(&P(;'`(<'$(<2`@<')I;G1S(&$@;&ES
- M=&EN9R!O9B!T:&4@:F]B<R!Q=65U960@9F]R('1H870@<&%R=&EC=2T*("`@
- M("`@(&QA<B!P<FEN=&5R+B`@5&AE("T(+6P(;"!O<'1I;VX@<')I;G1S(&$@
- M;6]R92!V97)B;W-E(&QI<W1I;F<N"@I%"$5."$Y6"%9)"$E2"%)/"$]."$Y-
- M"$U%"$5."$Y4"%0*("`@("`@(&P(;'`(<'((<B!R97%U:7)E<R!T:&%T('1H
- M92!,"$Q0"%!$"$1?"%]3"%-%"$52"%)6"%9%"$52"%(@96YV:7)O;FUE;G0@
- M=F%R:6%B;&4@8V]N+0H@("`@("`@=&%I;B!T:&4@;F%M92!O9B!A("!P<FEN
- M=&5R("!S97)V97(@('1O("!W:&EC:"`@9FEL97,@(&%R90H@("`@("`@<W!O
- M;VQE9"X@("!)9B`@=&AI<R!V87)I86)L92!D;V5S(&YO="!E>&ES="P@86X@
- M97)R;W(@;65S+0H@("`@("`@<V%G92!I<R!P<FEN=&5D+@H*3PA/4`A05`A4
- M20A)3PA/3@A.4PA3"B`@("`@("!/<'1I;VYS(&9A;&P@:6YT;R!T=V\@9V5N
- M97)A;"!C871E9V]R:65S.B`@:F]B(&]P=&EO;G,@86YD"B`@("`@("!F:6QE
- M("!O<'1I;VYS+B`@(%1H92`@9F]R;65R("!C;&%S<R`@;V8@;W!T:6]N<R!A
- M9F9E8W1S(&%N"B`@("`@("!E;G1I<F4@<')I;G0@:F]B+B`@5&AE(&QA='1E
- M<B!C;&%S<R!A9F9E8W1S(&]N;'D@('-P96-I9FEC"B`@("`@("!F:6QE<R`@
- M86YD("!C86X@(&)E("!O=F5R<FED96X@(&9O<B!S=6)S97%U96YT(&9I;&5S
- M+B`@1F]R"B`@("`@("!E>&%M<&QE+"!I="!I<R!P;W-S:6)L92!T;R!P<FEN
- M="!A('1R;V9F(&9I;&4@86YD(&$@('!L86EN"B`@("`@("!T97AT(&9I;&4@
- M:6X@=&AE('-A;64@<')I;G0@:F]B+@H*("`@("`@($]P=&EO;G,@('1H870@
- M(')E<75I<F4@(&%R9W5M96YT<R!C86X@8F4@<W!E8VEF:65D('=I=&@@;W(*
- M("`@("`@('=I=&AO=70@:6YT97)V96YI;F<@<W!A8V4@8F5T=V5E;B!T:&4@
- M;W!T:6]N(&%N9"!T:&4@87)G=2T*("`@("`@(&UE;G0N("!4:'5S+"!E:71H
- M97(@+0@M4`A07PAP7PAR7PAI7PAN7PAT7PAE7PAR(&]R("T(+5`(4"!?"'!?
- M"')?"&E?"&Y?"'1?"&5?"'(@=VEL;"!W;W)K+@H*("`@2@A*;PAO8@AB(&\(
- M;W`(<'0(=&D(:6\(;VX(;G,(<PH@("`@("`@5&AE<V4@(&]P=&EO;G,@('-P
- M96-I9GD@('!A<F%M971E<G,@=&AA="!A9F9E8W0@=&AE(&5N=&ER90H@("`@
- M("`@<')I;G0@:F]B+B`@5&AE<V4@:6YC;'5D93H*"@H*"B`@("`@("`@("`@
- M("`@("`@("`@("`@("`@,C$@36%R8V@@,3DY,2`@("`@("`@("`@("`@("`@
- M("`@("`@("`Q"@H*"@H*3%!2*#$I("`@("`@("`@("`@("`@("`@("`@("`@
- M("`@("`@("`@("`@("`@("`@("`@("`@("`@("!,4%(H,2D*"@H@("`@("`@
- M+0@M0PA#7PAJ7PAO7PAB7PAC7PAL7PAA7PAS7PAS("`@("!.86UE<R!T:&4@
- M:F]B(&-L87-S+"!W:&EC:"!W:6QL("!A<'!E87(@(&]N"B`@("`@("`@("`@
- M("`@("`@("`@("!T:&4@(&IO8B`@8F%N;F5R("!P86=E+B`@0GD@9&5F875L
- M="!T:&ES(&ES"B`@("`@("`@("`@("`@("`@("`@("!S970@=&\@=&AE(&QO
- M8V%L(&AO<W1N86UE+@H*("`@("`@("T(+4H(2E\(:E\(;U\(8E\(=%\(:5\(
- M=%\(;%\(92`@("`@3F%M97,@=&AE(&IO8B!T:71L92P@=VAI8V@@=VEL;"`@
- M87!P96%R("!O;@H@("`@("`@("`@("`@("`@("`@("`@=&AE("!J;V(@(&)A
- M;FYE<B`@<&%G92`@=VAE;B`@<')I;G1E9"X@("!">0H@("`@("`@("`@("`@
- M("`@("`@("`@9&5F875L="!T:&ES(&ES('1H92!N86UE(&]F('1H92!F:7)S
- M="`@9FEL90H@("`@("`@("`@("`@("`@("`@("`@;F%M960@;VX@=&AE(&-O
- M;6UA;F0@;&EN92X*"B`@("`@("`M""UH"&@@("`@("`@("`@("`@5&5L;',@
- M('1H92`@<')I;G1E<B!S97)V97(@=&\@;F]T('!R:6YT('1H90H@("`@("`@
- M("`@("`@("`@("`@("`@8F%N;F5R('!A9V4N"@H@("`@("`@+0@M;0AM("`@
- M("`@("`@("`@(%=H96X@=&AE("!P<FEN="`@:F]B("!C;VUP;&5T97,L("!H
- M879E("!T:&4*("`@("`@("`@("`@("`@("`@("`@('!R:6YT97(@('-E<G9E
- M<B`@<V5N9"!A(&UA:6P@;65S<V%G92!T;R!T:&4*("`@("`@("`@("`@("`@
- M("`@("`@('!E<G-O;B`@=VAO("!S=6)M:71T960@("!T:&4@("!J;V(N("`@
- M(%1H:7,*("`@("`@("`@("`@("`@("`@("`@(')E<75I<F5S("!T:&%T("!Y
- M;W5R("!M86-H:6YE("!B92`@86)L92`@=&\*("`@("`@("`@("`@("`@("`@
- M("`@(')E8V5I=F4@(&UA:6P@("!A9&1R97-S960@("!T;R`@(%\(>5\(;U\(
- M=5\(<E\(+5\(=5\(<U\(95\(<E\(+0H@("`@("`@("`@("`@("`@("`@("`@
- M7PAN7PAA7PAM7PAE0%\(>5\(;U\(=5\(<E\(+5\(:%\(;U\(<U\(=%\(+5\(
- M;E\(85\(;5\(92`@(&%N9"`@=&AA="`@=&AE("!P<FEN=`H@("`@("`@("`@
- M("`@("`@("`@("`@<V5R=F5R(&)E(&%B;&4@=&\@9V5T(&ET('1H97)E+@H*
- M("`@("`@("T(+5`(4%\(<%\(<E\(:5\(;E\(=%\(95\(<B`@("`@('-P96-I
- M9FEE<R`@=&\@('=H:6-H("!P<FEN=&5R("`@*&]F("`@=&AO<V4*("`@("`@
- M("`@("`@("`@("`@("`@(&%T=&%C:&5D('1O('1H92!P<FEN=&5R('-E<G9E
- M<BD@;W5T<'5T('=I;&P*("`@("`@("`@("`@("`@("`@("`@(&)E('-E;G0N
- M"@H@("`@("`@+0@M<0AQ7PAP7PAR7PAI7PAN7PAT7PAE7PAR("`@("`@5&AE
- M("T(+7$(<2!O<'1I;VX@:7,@('-Y;F]N>6UO=7,@('=I=&@@('1H92`@+0@M
- M4`A0"B`@("`@("`@("`@("`@("`@("`@("!O<'1I;VXN("`@5&AI<R`@;W!T
- M:6]N("!I<R!I;G1E;F1E9"!F;W(@=7-E"B`@("`@("`@("`@("`@("`@("`@
- M("!W:71H(%9-4R!S>7-T96US('1H870@8V%N;F]T(&1I<W1I;F=U:7-H("T(
- M+5`(4`H@("`@("`@("`@("`@("`@("`@("`@9G)O;2`@+0@M<`AP+@@N("!3
- M"%-I"&EN"&YC"&-E"&4@+0@M<`AP(&AA<R!A;F]T:&5R(&UE86YI;F<L("T(
- M+7$(<0H@("`@("`@("`@("`@("`@("`@("`@:7,@=7-E9"!O;B!635,@=&\@
- M<V5L96-T('1H92!P<FEN=&5R+B`@(%9-4PH@("`@("`@("`@("`@("`@("`@
- M("`@=7-E<G,@8V%N(&%L<V\@='EP92`M""U0"%!?"'!?"')?"&E?"&Y?"'1?
- M"&5?"'(@=VET:&EN(&1O=6)L90H@("`@("`@("`@("`@("`@("`@("`@<75O
- M=&5S+@H*("`@("`@("T(+7((<B`@("`@("`@("`@("!S<&5C:69I97,@=&AA
- M="!T:&4@;F%M960@9FEL97,@(&%R92`@=&\@(&)E"B`@("`@("`@("`@("`@
- M("`@("`@("!R96UO=F5D("!A9G1E<B!B96EN9R!S=6-C97-S9G5L;'D@=')A
- M;G-M:70M"B`@("`@("`@("`@("`@("`@("`@("!T960@=&\@=&AE(')E;6]T
- M92!P<FEN=&5R('-P;V]L97(N"@H@("`@("`@+0@M9`AD90AE8@AB=0AU9PAG
- M("`@("`@("`@4VAO=R!M97-S86=E<R!S96YT('1O(&%N9"!F<F]M("!T:&4@
- M('-E<G9E<@H@("`@("`@("`@("`@("`@("`@("`@;VX@('1H92!S=&%N9&%R
- M9"!E<G)O<B!O=71P=70N("!.;W0@9F]R('1H90H@("`@("`@("`@("`@("`@
- M("`@("`@9F%I;G0M;V8M:&5A<G0N"@H@("!&"$9I"&EL"&QE"&4@;PAO<`AP
- M=`AT:0AI;PAO;@AN<PAS"B`@("`@("!4:&5S92!O<'1I;VYS('-P96-I9GD@
- M<&%R86UE=&5R<R!T:&%T("!A<F4@('!A<G1I8W5L87(@('1O"B`@("`@("!O
- M;F4@(&]R("!M;W)E("!O9B`@=&AE(&9I;&5S('1O(&)E('!R:6YT960N("!4
- M:&5S92!O<'1I;VYS"B`@("`@("!P97)T86EN('1O(&%N>2!F:6QE<R!T:&%T
- M("!A<'!E87(@('1O("!T:&4@(')I9VAT("!O9B`@=&AE"B`@("`@("!O<'1I
- M;VX@(&]N("!T:&4@8V]M;6%N9"!L:6YE+"!B=70@=&AE>2!M87D@8F4@;W9E
- M<G)I9&5N(&)Y"B`@("`@("!S<&5C:69I;F<@82!D:69F97)E;G0@;W!T:6]N
- M(&)E='=E96X@9FEL97,N"@H@("`@("`@3VYL>2!O;F4@;V8@=&AE(&9I;&4M
- M='EP92!O<'1I;VYS("@M""UD"&0L("T(+68(9BP@+0@M9PAG+"`M""UL"&PL
- M("T(+6X(;BP@+0@M;PAO+`H@("`@("`@+0@M<`AP+"`@+0@M=`AT+"`@86YD
- M("T(+78(=BD@87!P;'D@=&\@86YY(&=I=F5N(&9I;&4N("!3=6)S97%U96YT
- M('5S90H@("`@("`@;V8@86YY(&]F('1H97-E(&]P=&EO;G,@<W!E8VEF:65S
- M('1H92!T>7!E("!O9B`@96%C:"`@9FEL90H@("`@("`@=&AA="`@87!P96%R
- M<R`@=&\@('1H92`@<FEG:'0@;V8@=&AE(&]P=&EO;BP@=6YT:6P@86YO=&AE
- M<@H@("`@("`@9FEL92UT>7!E(&]P=&EO;B!A<'!E87)S+@H*("`@("`@($EN
- M('1H92!A8G-E;F-E(&]F(&%N>2`@9FEL92UT>7!E("!O<'1I;VYS+"`@;`AL
- M<`AP<@AR("!T<FEE<R`@=&\*"@H*("`@("`@("`@("`@("`@("`@("`@("`@
- M("`R,2!-87)C:"`Q.3DQ("`@("`@("`@("`@("`@("`@("`@("`@(#(*"@H*
- M"@I,4%(H,2D@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@
- M("`@("`@("`@("`@("`@($Q04B@Q*0H*"B`@("`@("!F:6=U<F4@(&]U="`@
- M=VAA="`@:VEN9"`@;V8@9FEL92!I<R!T;R!B92!P<FEN=&5D+B`@270@8V%N
- M"B`@("`@("!C=7)R96YT;'D@<F5C;V=N:7IE("!415@@($1622`@9FEL97,L
- M("!A<R`@=V5L;"`@87,@($,O02]4"B`@("`@("`H8&!C;&%S<VEC)R<I("!T
- M"'1R"')O"&]F"&9F"&8H,2D@86YD(%!O<W138W)I<'0@9FEL97,N("!)9B!T
- M:&4@<&%R+0H@("`@("`@=&EC=6QA<B!K:6YD(&]F(&9I;&4@:7,@;F]T(')E
- M8V]G;FEZ960L("!L"&QP"'!R"'(@(&%S<W5M97,@('1H90H@("`@("`@9FEL
- M92!I<R!A;B!O<F1I;F%R>2!T97AT(&9I;&4N"@H@("`@("`@+0@M(P@C7PAN
- M7PAU7PAM7PAB7PAE7PAR("`@("`@(%-P96-I9FEE<R!T:&4@;G5M8F5R(&]F
- M(&-O<&EE<R!O9B!E86-H(&9I;&4*("`@("`@("`@("`@("`@("`@("`@('1O
- M('!R:6YT+B`@1&5F875L="!I<R!T;R!P<FEN="!O;F4@8V]P>2`@;V8*("`@
- M("`@("`@("`@("`@("`@("`@(&5A8V@@9FEL92X*"B`@("`@("`M""UD"&0@
- M("`@("`@("`@("`@1FEL97,@('1H870@(&9O;&QO=R!T:&ES(&]P=&EO;B!A
- M<F4@9&5V:6-E+0H@("`@("`@("`@("`@("`@("`@("`@:6YD97!E;F1E;G0@
- M*$1622D@9FEL97,@<W5C:"`@87,@(&UI9VAT("!B90H@("`@("`@("`@("`@
- M("`@("`@("`@<')O9'5C960@8GD@5$58+@H*("`@("`@("T(+68(9B`@("`@
- M("`@("`@("!496QL<R!L"&QP"'!R"'(@=&\@97AP96-T(&9I;&5S(&EN($9/
- M4E1204X@;W5T<'5T"B`@("`@("`@("`@("`@("`@("`@("!F;W)M870L('=H
- M97)E('1H92!F:7)S="!C:&%R86-T97(@(&]F("!E86-H"B`@("`@("`@("`@
- M("`@("`@("`@("!L:6YE(&1E=&5R;6EN97,@:&]W('1O(&AA;F1L92!T:&4@
- M8&!P<FEN=&5R"B`@("`@("`@("`@("`@("`@("`@("!C87)R86EG92<G(&%F
- M=&5R("!E86-H("!L:6YE("`H4PA34`A000A!0PA#10A%/6=O("!T;PH@("`@
- M("`@("`@("`@("`@("`@("`@;F5X="!L:6YE+"!@8"L(*R<G/6]V97)P<FEN
- M="P@971C+BD*"B`@("`@("`M""UG"&<@("`@("`@("`@("`@1FEL97,@('1H
- M870@9F]L;&]W('1H:7,@;W!T:6]N(&%R92!E>'!E8W1E9`H@("`@("`@("`@
- M("`@("`@("`@("`@=&\@8F4@:6X@5C<@54Y)6"!P"'!L"&QO"&]T"'0H-2D@
- M9F]R;6%T+B`@*%9E<GD@9F5W"B`@("`@("`@("`@("`@("`@("`@("!S<&]O
- M;&5R<R!S=7!P;W)T('1H:7,@9F]R;6%T+BD*"B`@("`@("`M""UL"&P@("`@
- M("`@("`@("`@1FEL97,@('1H870@9F]L;&]W('1H:7,@;W!T:6]N(&%R92!O
- M<F1I;F%R>0H@("`@("`@("`@("`@("`@("`@("`@=&5X="!F:6QE<RP@8G5T
- M('=H:6-H(&UA>2!C;VYT86EN("!E;6)E9&1E9`H@("`@("`@("`@("`@("`@
- M("`@("`@8V]N=')O;"!C:&%R86-T97)S+B`@*%-O;64@<')I;G1E<B!S<&]O
- M;&5R<PH@("`@("`@("`@("`@("`@("`@("`@<F5J96-T(&9I;&5S('=H:6-H
- M(&-O;G1A:6X@=&]O(&UA;GD@8V]N=')O;`H@("`@("`@("`@("`@("`@("`@
- M("`@8VAA<F%C=&5R<SL@=&AI<R!O<'1I;VX@;W9E<G)I9&5S('1H870@9F5A
- M+0H@("`@("`@("`@("`@("`@("`@("`@='5R92!I;B!O<F1E<B!T;R!A;&QO
- M=R!U<V5R<R!T;R!M86ME('5S92!O9@H@("`@("`@("`@("`@("`@("`@("`@
- M<')I;G1E<B`@<W!E8VEF:6,@9F5A='5R97,@=&AA="!R97%U:7)E('5S90H@
- M("`@("`@("`@("`@("`@("`@("`@;V8@;F]N+7!R:6YT86)L92!C:&%R86-T
- M97)S+BD*"B`@("`@("`M""UN"&X@("`@("`@("`@("`@5&5L;',@(&P(;'`(
- M<'((<B`@=&\@(&5X<&5C="`@9FEL97,@(&EN("`@9&5V:6-E+0H@("`@("`@
- M("`@("`@("`@("`@("`@:6YD97!E;F1E;G0@('1R;V9F("AD"&1I"&ET"'1R
- M"')O"&]F"&9F"&8I(&9O<FUA="X@("A-86YY"B`@("`@("`@("`@("`@("`@
- M("`@("!S<&]O;&5R<R!D;R!N;W0@<W5P<&]R="!T:&ES(&9O<FUA="XI"@H@
- M("`@("`@+0@M;PAO("`@("`@("`@("`@(%1E;&QS(&P(;'`(<'((<B!T;R!E
- M>'!E8W0@4&]S=%-C<FEP="!F:6QE<RX@(%1H:7,*("`@("`@("`@("`@("`@
- M("`@("`@(&=E;F5R86QL>2`@<F5Q=6ER97,@=&AA="!T:&4@<')I;G1E<B!I
- M='-E;&8*("`@("`@("`@("`@("`@("`@("`@('-P96%K("`@4&]S=%-C<FEP
- M="X@("`@1G5R=&AE<FUO<F4L("`@(&UA;GD*("`@("`@("`@("`@("`@("`@
- M("`@('!R:6YT97(@('-P;V]L97)S("!D;R`@;F]T("!G<F]K("T(+6\(;RP@
- M8G5T(&1O"B`@("`@("`@("`@("`@("`@("`@("!A8V-E<'0@4&]S=%-C<FEP
- M="!F:6QE<R!S=6)M:71T960@87,@8&!N;W(M"B`@("`@("`@("`@("`@("`@
- M("`@("!M86P@('1E>'0G)R`@9FEL97,L("!I;G1E<G!R971I;F<@('1H96T@
- M(&%S"B`@("`@("`@("`@("`@("`@("`@("!0;W-T4V-R:7!T('!R;V=R86US
- M("!R871H97(@('1H86X@(&]R9&EN87)Y"B`@("`@("`@("`@("`@("`@("`@
- M("!T97AT(&9I;&5S+@H*("`@("`@("T(+7`(<"`@("`@("`@("`@("!496QL
- M<R`@;`AL<`AP<@AR("!T:&%T('-U8G-E<75E;G0@9FEL97,@87)E(&]R9&DM
- M"B`@("`@("`@("`@("`@("`@("`@("!N87)Y('1E>'0@9FEL97,L('=H:6-H
- M("!S:&]U;&0@(&)E("!P<FEN=&5D"B`@("`@("`@("`@("`@("`@("`@("!W
- M:71H('!A9V4@8G)E86MS(&%N9"!H96%D97)S+@H*("`@("`@("T(+70(="`@
- M("`@("`@("`@("!496QL<R`@;`AL<`AP<@AR("!T;R!E>'!E8W0@9FEL97,@
- M9V5N97)A=&5D(&9O<B!A"B`@("`@("`@("`@("`@("`@("`@("!#+T$O5"!P
- M:&]T;W1Y<&5S971T97(L('-U8V@@87,@(&%R92`@9V5N97(M"B`@("`@("`@
- M("`@("`@("`@("`@("!A=&5D(&)Y(&]L9"!O<B!@8&-L87-S:6,G)R!T"'1R
- M"')O"&]F"&9F"&8N"@H*"@H@("`@("`@("`@("`@("`@("`@("`@("`@(#(Q
- M($UA<F-H(#$Y.3$@("`@("`@("`@("`@("`@("`@("`@("`@,PH*"@H*"DQ0
- M4B@Q*2`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@
- M("`@("`@("`@("`@3%!2*#$I"@H*("`@("`@("T(+78(=B`@("`@("`@("`@
- M("!496QL<R`@;`AL<`AP<@AR('1O(&5X<&5C="!697)S871E8R!R87-T97(M
- M9F]R;6%T"B`@("`@("`@("`@("`@("`@("`@("!F:6QE<RP@;W(@9FEL97,@
- M(&EN("!T:&4@('!R:6YT97(G<R`@;F%T:79E"B`@("`@("`@("`@("`@("`@
- M("`@("!F;W)M870L('=H871E=F5R('1H870@:7,N"@I$"$1)"$E!"$%'"$=.
- M"$Y/"$]3"%-4"%1)"$E#"$-3"%,*("`@("`@($P(3%`(4$0(1%\(7U,(4T4(
- M15((4E8(5D4(15((4B!E"&5N"&YV"'9I"&ER"')O"&]N"&YM"&UE"&5N"&YT
- M"'0@=@AV80AA<@AR:0AI80AA8@AB;`AL90AE(&D(:7,(<R!N"&YO"&]T"'0@
- M<PAS90AE=`AT"B`@("`@("`@("`@(%1H92`@96YV:7)O;FUE;G0@('9A<FEA
- M8FQE("!,"$Q0"%!$"$1?"%]3"%-%"$52"%)6"%9%"$52"%(@;75S="!B92!S
- M970@=&\*("`@("`@("`@("`@=&AE(&YA;64@;V8@=&AE('!R:6YT97(@<V5R
- M=F5R+@H*("`@("`@(&((8FD(:6X(;F0(9#H(.B!C"&-A"&%N"&YN"&YO"&]T
- M"'0@8@AB:0AI;@AN9`AD('0(=&\(;R!P"'!R"')I"&EV"'9I"&EL"&QE"&5G
- M"&=E"&5D"&0@<`AP;PAO<@AR=`AT"B`@("`@("`@("`@($5I=&AE<B!N;R`@
- M<')I=FEL96=E9"`@<&]R=',@(&%R92`@879A:6QA8FQE("`H:&EG:&QY"B`@
- M("`@("`@("`@('5N;&EK96QY*2P@(&]R("!L"&QP"'!R"'(@(&ES(&YO="!I
- M;G-T86QL960@87,@82!P<FEV:6QE9V5D"B`@("`@("`@("`@('!R;V=R86TN
- M("`@5&5L;"`@>6]U<B`@<WES=&5M("!M86YA9V5R("!T;R`@<F5A9"`@=&AE
- M"B`@("`@("`@("`@(&EN<W1A;&QA=&EO;B!I;G-T<G5C=&EO;G,@86=A:6XN
- M"@H@("`@("`@8PAC80AA;@AN)P@G=`AT(&8(9FD(:6X(;F0(9"!N"&YE"&5T
- M"'1W"'=O"&]R"')K"&L@80AA9`AD9`AD<@AR90AE<PAS<PAS(&8(9F\(;W((
- M<B!?"'-?"&5?"')?"'9?"&5?"'(*("`@("`@("`@("`@06X@(&%T=&5M<'0@
- M('1O("!D971E<FUI;F4@=&AE(&YE='=O<FL@861D<F5S<R!O9B!T:&4*("`@
- M("`@("`@("`@<')I;G1E<B!S97)V97(@9F%I;&5D+B`@5&AE('-E<G9E<B!M
- M=7-T(&)E(&QI<W1E9"`@:6X*("`@("`@("`@("`@=&AE("!);G1E<FYE="`@
- M;F%M92`@<V5R=F5R+"!Y;W5R('-Y<W1E;2=S("\(+V4(970(=&,(8R\(+V@(
- M:&\(;W,(<W0(=',(<PH@("`@("`@("`@("!F:6QE+"!O<B!I;B!T:&4@($Y)
- M4R`@:&]S=',@(&1A=&%B87-E+"`@9&5P96YD:6YG("!O;@H@("`@("`@("`@
- M("!W:&EC:"!M96-H86YI<VT@>6]U<B!S>7-T96T@=7-E<R!F;W(@=')A;G-L
- M871I;F<@:&]S=`H@("`@("`@("`@("!N86UE<R!T;R!N971W;W)K(&%D9')E
- M<W-E<RX*"B`@("`@("!?"&9?"&E?"&Q?"&5?"&Y?"&%?"&U?"&4@:0AI<PAS
- M(&$(82!4"%1E"&58"%@@+@@N9`AD=@AV:0AI(&8(9FD(:6P(;&4(92P(+"!A
- M"&%S"'-S"'-U"'5M"&UI"&EN"&YG"&<@+0@M9`AD"B`@("`@("`@("`@(%1H
- M92!N86UE9"!F:6QE(&)E9VEN<R!A;F0@96YD<R!W:71H('1H92!M86=I8R!N
- M=6UB97)S"B`@("`@("`@("`@('5S960@(&)Y("!415@@1%9)(&9I;&5S+"!A
- M;F0@=VEL;"!T:&5R969O<F4@8F4@:6YT97(M"B`@("`@("`@("`@('!R971E
- M9"!A<R!S=6-H(&EN<W1E860@(&]F("!S<&5W:6YG("!G87)B86=E("!T;R`@
- M=&AE"B`@("`@("`@("`@('!R:6YT97(N"@H@("`@("`@7PAF7PAI7PAL7PAE
- M7PAN7PAA7PAM7PAE(&D(:7,(<R!A"&$@0PA#+P@O00A!+P@O5`A4('0(='((
- M<F\(;V8(9F8(9B!O"&]U"'5T"'1P"'!U"'5T"'0@9@AF:0AI;`AL90AE+`@L
- M(&$(87,(<W,(<W4(=6T(;6D(:6X(;F<(9R`M""UT"'0*("`@("`@("`@("`@
- M5&AE("!F:6QE("!B96=I;G,@('=I=&@@=&AE(&UA9VEC(&YU;6)E<B!G96YE
- M<F%T960@8GD*("`@("`@("`@("`@0R]!+U0@*&!@8VQA<W-I8R<G*2!T"'1R
- M"')O"&]F"&9F"&8H,2DL(&%N9"!W:6QL("!T:&5R969O<F4@(&)E"B`@("`@
- M("`@("`@(&EN=&5R<')E=&5D(&%S('-U8V@N"@H@("`@("`@7PAF7PAI7PAL
- M7PAE7PAN7PAA7PAM7PAE(&D(:7,(<R!A"&$@50A53@A.20A)6`A8(&P(;&D(
- M:6((8G((<F$(87((<GD(>2!A"&%R"')C"&-H"&AI"&EV"'9E"&4@+0@M+0@M
- M(&D(:6<(9VX(;F\(;W((<FD(:6X(;F<(9R!I"&ET"'0*("`@("`@("`@("`@
- M;`AL<`AP<@AR("!R969U<V5S("!T;R`@<')I;G0@(&QI8G)A<GD@87)C:&EV
- M92!F:6QE<RP@<VEN8V4*("`@("`@("`@("`@=&AE<V4@=7-U86QL>2!C;VYT
- M86EN(&YO;BUP<FEN=&%B;&4@9&%T82X*"B`@("`@("!?"&9?"&E?"&Q?"&5?
- M"&Y?"&%?"&U?"&4@:0AI<PAS(&$(82!C"&-O"&]M"&UP"'!R"')E"&5S"'-S
- M"'-E"&5D"&0@9@AF:0AI;`AL90AE("T(+2T(+2!I"&EG"&=N"&YO"&]R"')I
- M"&EN"&YG"&<@:0AI=`AT"B`@("`@("`@("`@(%1H92!N86UE9"!F:6QE(&AA
- M<R!B965N(&-O;7!R97-S960@=VET:"`@8PAC;PAO;0AM<`AP<@AR90AE<PAS
- M<PAS*#$I+`H@("`@("`@("`@("!A;F0@(&-A;FYO="`@8F4@(&1I<F5C=&QY
- M('!R:6YT960@8GD@;`AL<`AP<@AR+B`@16ET:&5R('5S90H@("`@("`@("`@
- M("!U"'5N"&YC"&-O"&]M"&UP"'!R"')E"&5S"'-S"',H,2D@=&\@<F5S=&]R
- M92!T:&4@;W)I9VEN86P@9FEL92P@(&]R("!P:7!E"B`@("`@("`@("`@('1H
- M92!F:6QE('1H<F]U9V@@>@AZ8PAC80AA=`AT*#$I+@H*("`@("`@(',(<VL(
- M:VD(:7`(<'`(<&D(:6X(;F<(9R!Z"'IE"&5R"')O"&\@;`AL90AE;@AN9PAG
- M=`AT:`AH(&8(9FD(:6P(;&4(92!?"&9?"&E?"&Q?"&5?"&Y?"&%?"&U?"&4*
- M("`@("`@("`@("`@;`AL<`AP<@AR("!O<'1I;6EZ97,@=&AE('!R:6YT:6YG
- M(&]F(&%N(&5M<'1Y(&9I;&4@8GD@<VMI<"T*("`@("`@("`@("`@<&EN9R!T
- M:&4@9FEL92!E;G1I<F5L>2P@('1H=7,@('-A=FEN9R`@=')E97,@(&)Y("!N
- M;W0*("`@("`@("`@("`@<')I;G1I;F<@=6YW86YT960@8F%N;F5R('!A9V5S
- M+@H*("`@("`@(%\(9E\(:5\(;%\(95\(;E\(85\(;5\(92!I"&ES"',@;@AN
- M;PAO=`AT(&$(82!V"'9A"&%L"&QI"&ED"&0@+@@N9`AD=@AV:0AI(&8(9FD(
- M:6P(;&4(90H@("`@("`@("`@("!4:&4@("T(+60(9"`@;W!T:6]N("!W87,@
- M<W!E8VEF:65D+"!B=70@=&AE(&YA;65D(&9I;&4@:7,*("`@("`@("`@("`@
- M;F]T(&EN($1622!F;W)M870N"@H*"@H*("`@("`@("`@("`@("`@("`@("`@
- M("`@("`R,2!-87)C:"`Q.3DQ("`@("`@("`@("`@("`@("`@("`@("`@(#0*
- M"@H*"@I,4%(H,2D@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@
- M("`@("`@("`@("`@("`@("`@($Q04B@Q*0H*"D((0E4(54<(1U,(4PH@("`@
- M("`@5&AE<F4@:7,@8W5R<F5N=&QY(&YO('=A>2!T;R!D96QE=&4@82!P<FEN
- M="!J;V(@*&%N86QO9V]U<PH@("`@("`@=&\@('1H92!"4T0@;`AL<`AP<@AR
- M;0AM(&-O;6UA;F0I+"!N;W(@=&\@:6YQ=6ER92!O;B!T:&4@<W1A='5S(&]F
- M"B`@("`@("!T:&4@<')I;G0@<75E=64@*&%N86QO9W5S('1O('1H92!"4T0@
- M;`AL<`AP<0AQ(&-O;6UA;F0I+@H*("`@("`@(%1H92!P<F]T;V-O;"!U<V5D
- M(&)Y(&P(;'`(<'((<B!R97%U:7)E<R!T:&%T(&ET(&MN;W<@('1H92`@97AA
- M8W0*("`@("`@('-I>F4@;V8@82!F:6QE(&)E9F]R92!S96YD:6YG(&ET('1O
- M('1H92!P<FEN="!S<&]O;&5R+B`@26X*("`@("`@(&]R9&5R('1O(&-O;7!U
- M=&4@=&AE('-I>F4@;V8@(&$@(&9I;&4@('!I<&5D("!T;R`@<W1A;F1A<F0*
- M("`@("`@(&EN<'5T+"!A;F0@:6X@;W)D97(@=&\@=V]R:R!O;B!N;VXM54Y)
- M6"!S>7-T96US('=H:6-H(&-A;BT*("`@("`@(&YO="!D971E<FUI;F4@=&AE
- M(&5X86-T('-I>F4@;V8@82`@9FEL92P@(&P(;'`(<'((<B`@<F5A9',@(&5A
- M8V@*("`@("`@(&9I;&4@(&EN=&\@(&UE;6]R>2`@*&-O=6YT:6YG('1H92!B
- M>71E<R!A<R!I="!G;V5S*2!B969O<F4*("`@("`@('-E;F1I;F<@:70@=&\@
- M=&AE('-P;V]L97(N("!4:&5R969O<F4L(&9I;&5S("!L87)G97(@('1H86X*
- M("`@("`@(&%V86EL86)L92!M96UO<GD@8V%N;F]T(&)E('!R:6YT960N"@H@
- M("`@("`@3F]T("!A;&P@('!R:6YT97)S("!O<B`@<W!O;VQE<G,@('-U<'!O
- M<G0@(&%L;"!F:6QE('1Y<&5S+@H@("`@("`@5&AE<F4@:7,@;F\@86=R965M
- M96YT(&%M;VYG('1H92!V87)I;W5S('-P;V]L97)S(&%S('1O(&AO=PH@("`@
- M("`@=&\@=')E870@=&AE("T(+78(=B!F:6QE('1Y<&4N"@H@("`@("`@5&AE
- M("`M""U4"%0L("`M""UI"&DL("`M""US"',L("!A;F0@+0@M=PAW(&]P=&EO
- M;G,@;V8@0E-$(&P(;'`(<'((<B!A<F4@;F]T('-U<"T*("`@("`@('!O<G1E
- M9"X*"B`@("`@("!*;V(@;G5M8F5R<R!A<F4@:G5S="!I;F1E<&5N9&5N=&QY
- M+6=E;F5R871E9"`@<F%N9&]M("!N=6TM"B`@("`@("!B97)S(&)E='=E96X@
- M,"!A;F0@.3DY+"!S;R!C;VYF;&EC=',@8F5T=V5E;B!T=V\@:F]B<R!S=6(M
- M"B`@("`@("!M:71T960@;VX@=&AE('-A;64@:&]S="!A<F4@<&]S<VEB;&4N
- M"@H@("`@("`@5&AE(%9-4R!I;G1E<F9A8V4@:7,@8W)U9G1Y+B`@3%!2(&]N
- M(%9-4R!S:&]U;&0@=&%K92`@5DU3+0H@("`@("`@<W1Y;&4@(&]P=&EO;G,L
- M("!A;F0@<F5T=7)N(&$@<F5A<V]N86)L92!E<G)O<B!S=&%T=7,L(&)U=`H@
- M("`@("`@:70@9&]E<VXG="!D;R!T:&%T('EE="X*"E,(4T4(144(12!!"$%,
- M"$Q3"%-/"$\*("`@("`@(%\(3%\(:5\(;E\(92!?"'!?"')?"&E?"&Y?"'1?
- M"&5?"'(@7PAD7PAA7PAE7PAM7PAO7PAN(%\(<%\(<E\(;U\(=%\(;U\(8U\(
- M;U\(;%\(+"!?"%)?"$9?"$-?"#%?"#%?"#=?"#E?""X*"B`@("`@("!$;V-U
- M;65N=&%T:6]N(&9O<B!T:&4@<')I;G1E<B!S<&]O;&5R('EO=2!A<F4@=7-I
- M;F<@;VX@=&AE"B`@("`@("!P<FEN=&5R("!S97)V97(N("`@3VX@0E-$(%5.
- M25@@86YD('-O;64@;W1H97(@<WES=&5M<RP@<V5E"B`@("`@("!T:&4@;6%N
- M('!A9V5S(&9O<B!L"&QP"'!Q"'$H,2DL(&P(;'`(<'((<FT(;2@Q*2P@;`AL
- M<`AP8PAC*#@I+"!A;F0@;`AL<`AP9`AD*#@I+@H*"@H*"@H*"@H*"@H*"@H*
- M"@H*"@H*("`@("`@("`@("`@("`@("`@("`@("`@("`R,2!-87)C:"`Q.3DQ
- =("`@("`@("`@("`@("`@("`@("`@("`@(#4*"@H@
- `
- end
- END_OF_FILE
- if test 14024 -ne `wc -c <'lpr.cat'`; then
- echo shar: \"'lpr.cat'\" unpacked with wrong size!
- fi
- # end of 'lpr.cat'
- fi
- echo shar: End of shell archive.
- exit 0
-